RPFW.0.04 Built 9.pwn 163 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114
  1. // Developers notes
  2. /* # Coding guideline
  3. * Add +1 at the end of array declarations to visually account for null bit.
  4. * Always log first.
  5. * Always notify discord last.
  6. * Always wait for other queries to finish before initiating one: "sql_wait(sqlHandle); // Wait for other queries to finish"
  7. * Delete GVar strings as soon as possible, but at least before the player quits or the gamemode exits, as per: https://forum.sa-mp.com/showthread.php?t=151076
  8. */
  9. /* # Style guide
  10. * GLOBAL_CONSTANT
  11. * local_variable
  12. * someFunction
  13. * SomeClass
  14. * playerid // Variable storing in-game player ID
  15. * player_id // Variable storing database player ID
  16. */
  17. /* # Adding a discord bot to your guild.
  18. https://discordapp.com/oauth2/authorize?client_id=%CLIENT_ID%&scope=bot&permissions=3072
  19. Where %CLEINT_ID% is the client id.
  20. */
  21. /* # To do:
  22. * Add geoiplib, to make connect messages fancier, and add a locate command.
  23. * Show underscores as spaces and convert spaces in changename input to undescores before regex chack.
  24. * Vip limit on characters.
  25. * See why sql_insert_id wont work.
  26. * Add all ADMIN_ECHO_CHANNEL messages to admin chat. (not the real admin chat)
  27. * Check if timestamps work (implemented on temp ban), before implementing it more.
  28. * Normalise database column names.
  29. * Some SMALLINT fields are using SQL_INTERGER_LEGNTH for size and could be smaller.
  30. */
  31. /// Global definitions
  32. // Colours
  33. /*
  34. #define COLOR_GREEN 0x33AA33AA
  35. #define COLOR_YELLOW 0xFFFF00AA
  36. #define COLOR_WHITE 0xFFFFFFAA
  37. #define COLOR_BLUE 0x0000BBAA
  38. #define COLOR_LIGHTBLUE 0x33CCFFAA
  39. #define COLOR_ORANGE 0xFF9900AA
  40. #define COLOR_RED 0xAA3333AA
  41. #define COLOR_LIME 0x10F441AA
  42. #define COLOR_NAVY 0x000080AA
  43. #define COLOR_AQUA 0xF0F8FFAA
  44. #define COLOR_CRIMSON 0xDC143CAA
  45. #define COLOR_BISQUE 0xFFE4C4AA
  46. #define COLOR_BLACK 0x000000AA
  47. #define COLOR_CHARTREUSE 0x7FFF00AA
  48. #define COLOR_BROWN 0XA52A2AAA
  49. #define COLOR_CORAL 0xFF7F50AA
  50. #define COLOR_GOLD 0xB8860BAA
  51. #define COLOR_GREENYELLOW 0xADFF2FAA
  52. #define COLOR_INDIGO 0x4B00B0AA
  53. #define COLOR_IVORY 0xFFFF82AA
  54. #define COLOR_LAWNGREEN 0x7CFC00AA
  55. #define COLOR_SEAGREEN 0x20B2AAAA
  56. #define COLOR_SEAGREEN 0x2E8B57AA
  57. #define COLOR_LIMEGREEN 0x32CD32AA //<--- Dark lime
  58. #define COLOR_MIDNIGHTBLUE 0X191970AA
  59. #define COLOR_MAROON 0x800000AA
  60. #define COLOR_OLIVE 0x808000AA
  61. #define COLOR_ORANGERED 0xFF4500AA
  62. #define COLOR_PINK 0xFFC0CBAA // - Light light pink
  63. #define COLOR_SPRINGGREEN 0x00FF7FAA
  64. #define COLOR_TOMATO 0xFF6347AA // - Tomato >:/ sounds wrong lol... well... :P
  65. #define COLOR_YELLOWGREEN 0x9ACD32AA //- like military green
  66. #define COLOR_MEDIUMAQUA 0x83BFBFAA
  67. #define COLOR_MEDIUMMAGENTA 0x8B008BAA // dark magenta ^^
  68. */
  69. #define COLOR_ACTIVEBORDER 0xB4B4B4FF
  70. #define COLOR_ACTIVECAPTION 0x99B4D1FF
  71. #define COLOR_ACTIVECAPTIONTEXT 0x000000FF
  72. #define COLOR_ALICEBLUE 0xF0F8FFFF
  73. #define COLOR_ANTIQUEWHITE 0xFAEBD7FF
  74. #define COLOR_APPWORKSPACE 0xABABABFF
  75. #define COLOR_AQUA 0x00FFFFFF
  76. #define COLOR_AQUAMARINE 0x7FFFD4FF
  77. #define COLOR_AZURE 0xF0FFFFFF
  78. #define COLOR_BEIGE 0xF5F5DCFF
  79. #define COLOR_BISQUE 0xFFE4C4FF
  80. #define COLOR_BLACK 0x000000FF
  81. #define COLOR_BLANCHEDALMOND 0xFFEBCDFF
  82. #define COLOR_BLUE 0x0000FFFF
  83. #define COLOR_BLUEVIOLET 0x8A2BE2FF
  84. #define COLOR_BROWN 0xA52A2AFF
  85. #define COLOR_BURLYWOOD 0xDEB887FF
  86. #define COLOR_BUTTONFACE 0xF0F0F0FF
  87. #define COLOR_BUTTONHIGHLIGHT 0xFFFFFFFF
  88. #define COLOR_BUTTONSHADOW 0xA0A0A0FF
  89. #define COLOR_CADETBLUE 0x5F9EA0FF
  90. #define COLOR_CHARTREUSE 0x7FFF00FF
  91. #define COLOR_CHOCOLATE 0xD2691EFF
  92. #define COLOR_CONTROL 0xF0F0F0FF
  93. #define COLOR_CONTROLDARK 0xA0A0A0FF
  94. #define COLOR_CONTROLDARKDARK 0x696969FF
  95. #define COLOR_CONTROLLIGHT 0xE3E3E3FF
  96. #define COLOR_CONTROLLIGHTLIGHT 0xFFFFFFFF
  97. #define COLOR_CONTROLTEXT 0x000000FF
  98. #define COLOR_CORAL 0xFF7F50FF
  99. #define COLOR_CORNFLOWERBLUE 0x6495EDFF
  100. #define COLOR_CORNSILK 0xFFF8DCFF
  101. #define COLOR_CRIMSON 0xDC143CFF
  102. #define COLOR_CYAN 0x00FFFFFF
  103. #define COLOR_DARKBLUE 0x00008BFF
  104. #define COLOR_DARKCYAN 0x008B8BFF
  105. #define COLOR_DARKGOLDENROD 0xB8860BFF
  106. #define COLOR_DARKGRAY 0xA9A9A9FF
  107. #define COLOR_DARKGREEN 0x006400FF
  108. #define COLOR_DARKKHAKI 0xBDB76BFF
  109. #define COLOR_DARKMAGENTA 0x8B008BFF
  110. #define COLOR_DARKOLIVEGREEN 0x556B2FFF
  111. #define COLOR_DARKORANGE 0xFF8C00FF
  112. #define COLOR_DARKORCHID 0x9932CCFF
  113. #define COLOR_DARKRED 0x8B0000FF
  114. #define COLOR_DARKSALMON 0xE9967AFF
  115. #define COLOR_DARKSEAGREEN 0x8FBC8BFF
  116. #define COLOR_DARKSLATEBLUE 0x483D8BFF
  117. #define COLOR_DARKSLATEGRAY 0x2F4F4FFF
  118. #define COLOR_DARKTURQUOISE 0x00CED1FF
  119. #define COLOR_DARKVIOLET 0x9400D3FF
  120. #define COLOR_DEEPPINK 0xFF1493FF
  121. #define COLOR_DEEPSKYBLUE 0x00BFFFFF
  122. #define COLOR_DEFAULT_CHAT 0xFFFFFFFF
  123. #define COLOR_DESKTOP 0x000000FF
  124. #define COLOR_DIMGRAY 0x696969FF
  125. #define COLOR_DODGERBLUE 0x1E90FFFF
  126. #define COLOR_FIREBRICK 0xB22222FF
  127. #define COLOR_FLBLUE 0x6495EDAA
  128. #define COLOR_FLORALWHITE 0xFFFAF0FF
  129. #define COLOR_FORESTGREEN 0x228B22FF
  130. #define COLOR_GAINSBORO 0xDCDCDCFF
  131. #define COLOR_GHOSTWHITE 0xF8F8FFFF
  132. #define COLOR_GOLD 0xFFD700FF
  133. #define COLOR_GOLDENROD 0xDAA520FF
  134. #define COLOR_GRADIENTACTIVECAPTION 0xB9D1EAFF
  135. #define COLOR_GRADIENTINACTIVECAPTION 0xD7E4F2FF
  136. #define COLOR_GRAY 0x808080FF
  137. #define COLOR_GRAYTEXT 0x808080FF
  138. #define COLOR_GREEN 0x008000FF
  139. #define COLOR_GREENYELLOW 0xADFF2FFF
  140. #define COLOR_GREY 0xAFAFAFAA
  141. #define COLOR_HIGHLIGHT 0x3399FFFF
  142. #define COLOR_HIGHLIGHTTEXT 0xFFFFFFFF
  143. #define COLOR_HONEYDEW 0xF0FFF0FF
  144. #define COLOR_HOTPINK 0xFF69B4FF
  145. #define COLOR_HOTTRACK 0x0066CCFF
  146. #define COLOR_INACTIVEBORDER 0xF4F7FCFF
  147. #define COLOR_INACTIVECAPTION 0xBFCDDBFF
  148. #define COLOR_INACTIVECAPTIONTEXT 0x434E54FF
  149. #define COLOR_INDIANRED 0xCD5C5CFF
  150. #define COLOR_INDIGO 0x4B0082FF
  151. #define COLOR_INFO 0xFFFFE1FF
  152. #define COLOR_INFOTEXT 0x000000FF
  153. #define COLOR_IVORY 0xFFFFF0FF
  154. #define COLOR_KHAKI 0xF0E68CFF
  155. #define COLOR_LAVENDER 0xE6E6FAFF
  156. #define COLOR_LAVENDERBLUSH 0xFFF0F5FF
  157. #define COLOR_LAWNGREEN 0x7CFC00FF
  158. #define COLOR_LEMONCHIFFON 0xFFFACDFF
  159. #define COLOR_LIGHTBLUE 0xADD8E6FF
  160. #define COLOR_LIGHTCORAL 0xF08080FF
  161. #define COLOR_LIGHTCYAN 0xE0FFFFFF
  162. #define COLOR_LIGHTGOLDENRODYELLOW 0xFAFAD2FF
  163. #define COLOR_LIGHTGRAY 0xD3D3D3FF
  164. #define COLOR_LIGHTGREEN 0x90EE90FF
  165. #define COLOR_LIGHTPINK 0xFFB6C1FF
  166. #define COLOR_LIGHTSALMON 0xFFA07AFF
  167. #define COLOR_LIGHTSEAGREEN 0x20B2AAFF
  168. #define COLOR_LIGHTSKYBLUE 0x87CEFAFF
  169. #define COLOR_LIGHTSLATEGRAY 0x778899FF
  170. #define COLOR_LIGHTSTEELBLUE 0xB0C4DEFF
  171. #define COLOR_LIGHTYELLOW 0xFFFFE0FF
  172. #define COLOR_LIME 0x00FF00FF
  173. #define COLOR_LIMEGREEN 0x32CD32FF
  174. #define COLOR_LINEN 0xFAF0E6FF
  175. #define COLOR_MAGENTA 0xFF00FFFF
  176. #define COLOR_MAROON 0x800000FF
  177. #define COLOR_MEDIUMAQUAMARINE 0x66CDAAFF
  178. #define COLOR_MEDIUMBLUE 0x0000CDFF
  179. #define COLOR_MEDIUMORCHID 0xBA55D3FF
  180. #define COLOR_MEDIUMPURPLE 0x9370DBFF
  181. #define COLOR_MEDIUMSEAGREEN 0x3CB371FF
  182. #define COLOR_MEDIUMSLATEBLUE 0x7B68EEFF
  183. #define COLOR_MEDIUMSPRINGGREEN 0x00FA9AFF
  184. #define COLOR_MEDIUMTURQUOISE 0x48D1CCFF
  185. #define COLOR_MEDIUMVIOLETRED 0xC71585FF
  186. #define COLOR_MENU 0xF0F0F0FF
  187. #define COLOR_MENUBAR 0xF0F0F0FF
  188. #define COLOR_MENUHIGHLIGHT 0x3399FFFF
  189. #define COLOR_MENUTEXT 0x000000FF
  190. #define COLOR_MIDNIGHTBLUE 0x191970FF
  191. #define COLOR_MINTCREAM 0xF5FFFAFF
  192. #define COLOR_MISTYROSE 0xFFE4E1FF
  193. #define COLOR_MOCCASIN 0xFFE4B5FF
  194. #define COLOR_NAVAJOWHITE 0xFFDEADFF
  195. #define COLOR_NAVY 0x000080FF
  196. #define COLOR_OLDLACE 0xFDF5E6FF
  197. #define COLOR_OLIVE 0x808000FF
  198. #define COLOR_OLIVEDRAB 0x6B8E23FF
  199. #define COLOR_ORANGE 0xFFA500FF
  200. #define COLOR_ORANGERED 0xFF4500FF
  201. #define COLOR_ORCHID 0xDA70D6FF
  202. #define COLOR_PALEGOLDENROD 0xEEE8AAFF
  203. #define COLOR_PALEGREEN 0x98FB98FF
  204. #define COLOR_PALETURQUOISE 0xAFEEEEFF
  205. #define COLOR_PALEVIOLETRED 0xDB7093FF
  206. #define COLOR_PAPAYAWHIP 0xFFEFD5FF
  207. #define COLOR_PEACHPUFF 0xFFDAB9FF
  208. #define COLOR_PERU 0xCD853FFF
  209. #define COLOR_PINK 0xFFC0CBFF
  210. #define COLOR_PLUM 0xDDA0DDFF
  211. #define COLOR_POWDERBLUE 0xB0E0E6FF
  212. #define COLOR_PURPLE 0x800080FF
  213. #define COLOR_RED 0xFF0000FF
  214. #define COLOR_ROSYBROWN 0xBC8F8FFF
  215. #define COLOR_ROYALBLUE 0x4169E1FF
  216. #define COLOR_SADDLEBROWN 0x8B4513FF
  217. #define COLOR_SALMON 0xFA8072FF
  218. #define COLOR_SANDYBROWN 0xF4A460FF
  219. #define COLOR_SCROLLBAR 0xC8C8C8FF
  220. #define COLOR_SEAGREEN 0x2E8B57FF
  221. #define COLOR_SEASHELL 0xFFF5EEFF
  222. #define COLOR_SIENNA 0xA0522DFF
  223. #define COLOR_SILVER 0xC0C0C0FF
  224. #define COLOR_SKYBLUE 0x87CEEBFF
  225. #define COLOR_SLATEBLUE 0x6A5ACDFF
  226. #define COLOR_SLATEGRAY 0x708090FF
  227. #define COLOR_SNOW 0xFFFAFAFF
  228. #define COLOR_SPRINGGREEN 0x00FF7FFF
  229. #define COLOR_STEELBLUE 0x4682B4FF
  230. #define COLOR_TAN 0xD2B48CFF
  231. #define COLOR_TEAL 0x008080FF
  232. #define COLOR_THISTLE 0xD8BFD8FF
  233. #define COLOR_TOMATO 0xFF6347FF
  234. #define COLOR_TRANSPARENT 0xFFFFFF00
  235. #define COLOR_TURQUOISE 0x40E0D0FF
  236. #define COLOR_VIOLET 0xEE82EEFF
  237. #define COLOR_WHEAT 0xF5DEB3FF
  238. #define COLOR_WHITE 0xFFFFFFFF
  239. #define COLOR_WHITESMOKE 0xF5F5F5FF
  240. #define COLOR_WINDOW 0xFFFFFFFF
  241. #define COLOR_WINDOWFRAME 0x646464FF
  242. #define COLOR_WINDOWTEXT 0x000000FF
  243. #define COLOR_YELLOW 0xFFFF00FF
  244. #define COLOR_YELLOWGREEN 0x9ACD32FF
  245. #define COLOR_STEALTH_ORANGE 0xFF880000
  246. #define COLOR_STEALTH_OLIVE 0x66660000
  247. #define COLOR_STEALTH_GREEN 0x33DD1100
  248. #define COLOR_STEALTH_PINK 0xFF22EE00
  249. #define COLOR_STEALTH_BLUE 0x0077BB00
  250. // Color groups
  251. #define COLOR_COMMAND_OUTPUT 0xFFFFFFFF // White
  252. #define COLOR_NOTICE 0xAFAFAFAA // Grey
  253. #define COLOR_WARNING 0xFFA500FF // Orange? (Looks more yellow to me)
  254. #define COLOR_ERROR 0xFF0000FF // Red
  255. #define COLOR_GLOBAL_CHAT 0xFFFFFFFF // White
  256. #define COLOR_PM_CHAT 0xFFFF00FF // Yellow
  257. #define COLOR_VIP_CHAT 0x800080FF // Purple
  258. #define COLOR_CREW_CHAT 0xFF9900AA // Orange
  259. #define COLOR_ADMIN_CHAT 0xB8860BAA // Gold
  260. #define COLOR_POLICE 0x00008BFF //
  261. #define COLOR_MEDIC 0xFFC0CBAA // Light pink
  262. #define COLOR_FIRE 0xAA3333AA // Red
  263. #define COLOR_SHERIFF 0xF5F5DCFF // Beige
  264. #define COLOR_FBI 0x000080AA // Navy
  265. #define COLOR_DMV 0xF0F8FFAA // Aqua
  266. #define COLOR_NEWS 0x808000FF // Olive
  267. #define EMBED_COLOR_GREY "{838383}"
  268. #define EMBED_COLOR_RED "{FF0000}"
  269. #define EMBED_COLOR_WHITE "{FFFFFF}"
  270. // SQL datatypes
  271. #define MAX_SQL_INTEGER 10
  272. #define MAX_SQL_TIMESTAMP 19 // 1999-01-08 04:05:06 [5 + 4 + 2 + 2 +2 + 2 + 2]
  273. #define MAX_SQL_FLOAT 16
  274. #define MAX_SQL_HASH 128
  275. #define MAX_SQL_IP 45
  276. #define MAX_SQL_REASON 121
  277. // Log levels
  278. #define LOGLEVEL_CHAT -2
  279. #define LOGLEVEL_COMMAND -1
  280. #define LOGLEVEL_DEBUG 0
  281. #define LOGLEVEL_INFO 1
  282. #define LOGLEVEL_NOTICE 2
  283. #define LOGLEVEL_WARNING 3
  284. #define LOGLEVEL_ERROR 4
  285. #define LOGLEVEL_CRITICAL 5
  286. #define LOGLEVEL_PANIC 6
  287. // Userlevels
  288. enum{ // Noted values as comments, for database reference.
  289. UNREGISTERED_PLAYER, // 0
  290. REGISTERED_PLAYER, // 1
  291. REGULAR_PLAYER, // 2 Spent many hours in and around the comunity.
  292. VIP_PLAYER, // 3 Donated.
  293. MODERATOR_CREW, // 4
  294. VETERAN_CREW, // 5 Inactive admins and management that are allowed to keep their rights.
  295. ADMIN_CREW, // 6
  296. UNDERCOVER_ADMIN_CREW, // 7
  297. MANAGEMENT_CREW, // 8
  298. UNDRECOVER_MANAGEMENT_CREW, // 9
  299. FOUNDER_PLAYER, // 10
  300. UNDERCOVER_FOUNDER_PLAYER, // 11
  301. }
  302. // Discord channels
  303. enum{
  304. ECHO_CHANNEL,
  305. MAIN_CHANNEL,
  306. ADMIN_ECHO_CHANNEL,
  307. ADMIN_CHANNEL,
  308. MANAGEMENT_CHANNEL,
  309. }
  310. // Chats
  311. enum{
  312. CHAT_LOCAL, // Has to be 0, else a gVar would have to be created OnJoin, this conserves memory when no chatmode is set (which will be the case most likely)
  313. CHAT_WHISPER,
  314. CHAT_LOW,
  315. CHAT_ACTION,
  316. CHAT_SHOUT,
  317. CHAT_OC,
  318. CHAT_GLOBAL,
  319. CHAT_CALL,
  320. CHAT_SMS,
  321. CHAT_RADIO,
  322. CHAT_PM,
  323. CHAT_GANG,
  324. CHAT_GANG_OC,
  325. CHAT_FACTION,
  326. CHAT_FACTION_OC,
  327. CHAT_VIP,
  328. CHAT_CREW,
  329. CHAT_ADMIN,
  330. CHAT_MANAGEMENT,
  331. CHAT_UNDERCOVER,
  332. }
  333. // Dialogs
  334. enum{
  335. DIALOG_CHANGENAME,
  336. DIALOG_REGISTER,
  337. DIALOG_ACCOUNT_CREATED,
  338. DIALOG_LOGIN,
  339. DIALOG_CHANGE_USERNAME,
  340. DIALOG_CHARACTERS,
  341. DIALOG_LOGIN_FAILED,
  342. DIALOG_DELETE_CHARACTER,
  343. DIALOG_GOTO,
  344. DIALOG_GOTO_INTERIOR,
  345. DIALOG_GOTO_PLAYER,
  346. DIALOG_GOTO_247,
  347. DIALOG_GOTO_AVIATION,
  348. DIALOG_GOTO_AMMUNATION,
  349. DIALOG_GOTO_BURGLARY,
  350. DIALOG_GOTO_MISSION,
  351. DIALOG_GOTO_MISSIONEXT,
  352. DIALOG_GOTO_MISSIONHOUSE,
  353. DIALOG_GOTO_MODDING,
  354. DIALOG_GOTO_POLICE,
  355. DIALOG_GOTO_HOUSE,
  356. DIALOG_GOTO_SHOP,
  357. DIALOG_GOTO_STADIA,
  358. DIALOG_CREATE_PICKUP,
  359. DIALOG_CREATE_FACTION_PICKUP,
  360. DIALOG_DUTY_PD,
  361. DIALOG_POLICE_SKIN,
  362. DIALOG_DUTY_MD,
  363. DIALOG_MEDIC_SKIN,
  364. DIALOG_DUTY_FD,
  365. DIALOG_FIRE_SKIN,
  366. DIALOG_DUTY_SD,
  367. DIALOG_SHERIFF_SKIN,
  368. DIALOG_DUTY_FBI,
  369. DIALOG_FBI_SKIN,
  370. DIALOG_DUTY_DMV,
  371. DIALOG_DMV_SKIN,
  372. DIALOG_DUTY_NEWS,
  373. DIALOG_NEWS_SKIN,
  374. }
  375. // Pickups
  376. enum{
  377. PICKUP_FACTION_PD,
  378. PICKUP_FACTION_MD,
  379. PICKUP_FACTION_FD,
  380. PICKUP_FACTION_SD,
  381. PICKUP_FACTION_FBI,
  382. PICKUP_FACTION_DMV,
  383. PICKUP_FACTION_NEWS,
  384. PICKUP_PORTAL, // MUST be last as it's not in the pickup create dialog
  385. }
  386. // Location categories
  387. enum{
  388. GOTO_CATEGORY_INTERIOR,
  389. }
  390. enum{
  391. INTERIOR_CATEGORY_247,
  392. INTERIOR_CATEGORY_AVIATION,
  393. INTERIOR_CATEGORY_AMMUNATION,
  394. INTERIOR_CATEGORY_BUGRLARY,
  395. INTERIOR_CATEGORY_MISSION,
  396. INTERIOR_CATEGORY_MISSIONEXT,
  397. INTERIOR_CATEGORY_MISSIONHOUSE,
  398. INTERIOR_CATEGORY_MODSHOP,
  399. INTERIOR_CATEGORY_POLICE,
  400. INTERIOR_CATEGORY_HOUSES,
  401. INTERIOR_CATEGORY_SHOPS,
  402. INTERIOR_CATEGORY_STADIA,
  403. }
  404. enum{INTERIOR_247_LSHAPED, INTERIOR_247_OBLONG, INTERIOR_247_MEDIUM, INTERIOR_247_MEDIUM_NOEXIT, INTERIOR_247_LONG, INTERIOR_247_SQAURE}
  405. enum{
  406. INTERIOR_AVIATION_TICKET,
  407. INTERIOR_AVIATION_BAGGAGE,
  408. INTERIOR_AVIATION_SHAMAL,
  409. INTERIOR_AVIATION_ANDROMADA,
  410. INTERIOR_AVIATION_LSAIRPORT
  411. }
  412. enum{INTERIOR_AMMU_OCEAN, INTERIOR_AMMU_PALOMINO, INTERIOR_AMMU_ANGEL, INTERIOR_AMMU_QUEBRADOS, INTERIOR_AMMU_2STORIES, INTERIOR_AMMU_BOOTH, INTERIOR_AMMU_RANGE}
  413. enum{
  414. INTERIOR_BURGRLARY_LARGE,
  415. INTERIOR_BURGRLARY_MEDIUM,
  416. INTERIOR_BURGRLARY_SMALL,
  417. INTERIOR_BURGRLARY_VERYLARGE,
  418. INTERIOR_BURGRLARY_5,
  419. INTERIOR_BURGRLARY_6,
  420. INTERIOR_BURGRLARY_NOBATH,
  421. }
  422. enum{
  423. INTERIOR_MISSION_ATRIUM,
  424. INTERIOR_MISSION_BIGSMOKE,
  425. INTERIOR_MISSION_JEFFERSON,
  426. INTERIOR_MISSION_JIZZY,
  427. INTERIOR_MISSION_RC,
  428. INTERIOR_MISSION_WUZI,
  429. }
  430. enum{
  431. INTERIOR_MISSIONEXT_GAS,
  432. INTERIOR_MISSIONEXT_LIBERTY,
  433. INTERIOR_MISSIONEXT_SFGARAGE,
  434. }
  435. enum{
  436. INTERIOR_MISSIONHOUSE_DESIRE,
  437. INTERIOR_MISSIONHOUSE_COLONEL,
  438. INTERIOR_MISSIONHOUSE_RYDER,
  439. INTERIOR_MISSIONHOUSE_SWEET,
  440. INTERIOR_MISSIONHOUSE_CRACK,
  441. }
  442. enum{INTERIOR_MOD_LOCO, INTERIOR_MOD_WHEEL, INTERIOR_MOD_TRANSFENDER}
  443. enum{INTERIOR_PD_LV, INTERIOR_PD_LS, INTERIOR_PD_SF, INTERIOR_PD_BARBARA}
  444. enum{
  445. INTERIOR_HOUSE_GOLDEN,
  446. INTERIOR_HOUSE_HASHBURY,
  447. INTERIOR_HOUSE_JOHNSON,
  448. INTERIOR_HOUSE_MADDDOGG,
  449. INTERIOR_HOUSE_RED,
  450. INTERIOR_HOUSE_VERDANT,
  451. INTERIOR_HOUSE_UNUSED,
  452. }
  453. enum{
  454. INTERIOR_SHOP_TATTOO,
  455. INTERIOR_SHOP_BURGER,
  456. INTERIOR_SHOP_PIZZA,
  457. INTERIOR_SHOP_CLUCKIN,
  458. INTERIOR_SHOP_CALIGULAS,
  459. INTERIOR_SHOP_CASINO,
  460. INTERIOR_SHOP_4DRAGONS,
  461. INTERIOR_SHOP_DONUTS,
  462. INTERIOR_SHOP_RC,
  463. INTERIOR_SHOP_PUMP,
  464. }
  465. enum{
  466. INTERIOR_STADIUM_BLOODBOWL,
  467. INTERIOR_STADIUM_KICKSTART,
  468. INTERIOR_STADIUM_8TRACK,
  469. INTERIOR_STADIUM_DIRTBIKE,
  470. }
  471. // Factions
  472. enum{
  473. FACTION_NONE,
  474. FACTION_POLICE,
  475. FACTION_MEDIC,
  476. FACTION_FIRE,
  477. FACTION_SHERIFF,
  478. FACTION_FBI,
  479. FACTION_DMV,
  480. FACTION_NEWS,
  481. }
  482. // Jobs
  483. enum{
  484. JOB_NONE,
  485. JOB_POLICE,
  486. JOB_MEDIC,
  487. JOB_FIRE,
  488. JOB_SHERIFF,
  489. JOB_FBI,
  490. JOB_DMV,
  491. JOB_NEWS,
  492. }
  493. // Environment settings TODO: THESE SHOULD ALL BE READ FROM A CONFIG FILE!
  494. static bool:scriptDebug = true; // Debug setting
  495. #define MODE_NAME "0.0a Build 9"
  496. #define SERVER_NAME "Bone County RPG"
  497. #define PG_HOST "127.0.0.1"
  498. #define PG_ROLE "rpfw-dev"
  499. #define PG_PASS "nJd&1k$0fs"
  500. #define PG_DB "rpfw-dev"
  501. #define PG_PORT 5432
  502. #define DISCORD_HOME_GUILD_ID "666077037470941184" // Emerald City Roleplay
  503. #define DISCORD_ECHO_CHANNEL_ID "677855051166777344" // #bcrp-echo
  504. //#define DISCORD_ECHO_CHANNEL_ID "666078187079598080" // #ecrp-echo
  505. #define DISCORD_MAIN_CHANNEL_ID "677855315898793984" // #bcrp
  506. //#define DISCORD_MAIN_CHANNEL_ID "667396220402270228" // #development
  507. #define DISCORD_ADMIN_ECHO_CHANNEL_ID "672841892169383936" // #admin-echo
  508. #define DISCORD_ADMIN_CHANNEL_ID "667396026058932236" // #admins
  509. #define DISCORD_MANAGEMENT_CHANNEL_ID "666091376240361492" // #management
  510. // Game-mode limits
  511. #define MAX_CHARACTERS_PER_USER 20 // Maximum of MAX_CHARACTERS_PER_USER_DIGITS digits (Due to SQL query string length)
  512. #define MAX_CHARACTERS_PER_USER_DIGITS 3
  513. // SQL plugin
  514. new SQL:sqlHandle;
  515. // discord-connector
  516. //static DCC_Guild:homeGuild; // Discord guild controlled by game community.
  517. static DCC_Channel:echoChannel; // Public echo channel.
  518. static DCC_Channel:mainChannel; // Channel for communirty notifications.
  519. static DCC_Channel:adminEchoChannel; // Admin echo channel.
  520. static DCC_Channel:adminChannel; // Channel for admin notifications.
  521. static DCC_Channel:managementChannel; // Channel for management notifications.
  522. DiscordEcho(const message[], messageLevel){ // Write to echo channels.
  523. switch(messageLevel) // Output facilities.
  524. {
  525. case ECHO_CHANNEL: { // Public echo message
  526. DiscordSendChannelMessage(echoChannel, message);
  527. DiscordSendChannelMessage(adminEchoChannel, message); // Also send to admin echo channel, so admin can see everything in one channel without needing to constantly switch. Also handy as log on conflicts/complaints.
  528. }
  529. case MAIN_CHANNEL: {DiscordSendChannelMessage(mainChannel, message);} // Public notification
  530. case ADMIN_ECHO_CHANNEL: {DiscordSendChannelMessage(adminEchoChannel, message);} // Admin echo message
  531. case ADMIN_CHANNEL: {DiscordSendChannelMessage(adminChannel, message);} // Admin notification
  532. case MANAGEMENT_CHANNEL: {DiscordSendChannelMessage(managementChannel, message);} // Management notification
  533. }
  534. return 0;
  535. }
  536. // Natives
  537. native WP_Hash(buffer[], len, const str[]); // https://forum.sa-mp.com/showthread.php?t=570945
  538. //native Float:loadavg(); // https://forum.sa-mp.com/showthread.php?t=260206 LINUX ONLY
  539. // Includes
  540. #include <a_samp> // https://sa-mp.com
  541. #include <sql> // https://github.com/udan11/samp-plugin-sql (Fastest player in town and only one supporting postgreSQL) | Examples: https://pastebin.com/67y2nq2n https://github.com/udan11/samp-plugin-sql/issues/10
  542. #include <sscanf2> // Newest version: https://github.com/maddinat0r/sscanf/releases | Better readme: https://github.com/Y-Less/sscanf
  543. #include <strlib> // https://github.com/oscar-broman/strlib
  544. #include <Pawn.Regex> // https://github.com/urShadow/Pawn.Regex
  545. #include <Pawn.CMD> // https://github.com/urShadow/Pawn.CMD (Fastest player in town)
  546. #include <gvar> // https://github.com/samp-incognito/samp-gvar-plugin
  547. #include <discord-connector> // https://github.com/maddinat0r/samp-discord-connector (Only player in town)
  548. #include <streamer> // https://github.com/samp-incognisto/samp-streamer-plugin
  549. /// Middle-ware
  550. // Logging
  551. logger(const log_level, const message[]){ // Write to logging facility
  552. // Do not log commands or debug when script debugging is turned off.
  553. if(scriptDebug == false){ // Debug is off
  554. if(log_level == LOGLEVEL_COMMAND || log_level == LOGLEVEL_DEBUG){ // Command or debug message
  555. return 0; // Stop and do not log
  556. }
  557. }
  558. // Messagelevel tag
  559. new human_readable_log_level[8 + 1];
  560. switch(log_level){ // Assign log level.
  561. case LOGLEVEL_CHAT: human_readable_log_level = "chat";
  562. case LOGLEVEL_COMMAND: human_readable_log_level = "command";
  563. case LOGLEVEL_DEBUG: human_readable_log_level = "debug";
  564. case LOGLEVEL_INFO: human_readable_log_level = "info";
  565. case LOGLEVEL_NOTICE: human_readable_log_level = "notice";
  566. case LOGLEVEL_WARNING: human_readable_log_level = "warning";
  567. case LOGLEVEL_ERROR: human_readable_log_level = "error";
  568. case LOGLEVEL_CRITICAL: human_readable_log_level = "critical";
  569. case LOGLEVEL_PANIC: human_readable_log_level = "panic";
  570. }
  571. printf("[%s] %s", human_readable_log_level, message); // Print to STDOUT.
  572. return 0;
  573. }
  574. /*// SQL plugin (BROKEN, look at it again after I have more then a week of experience)
  575. //forward sqlQuery(SQL:handle, query[]);
  576. //public sqlQuery(SQL:handle, query[]){
  577. sqlQuery(SQL:handle, query[]){
  578. //sql_wait(handle); // Wait for all queries to finish.
  579. new Result:result = sql_query(handle, query);
  580. if(sql_error(result)){printf("SQL error");} // Did not work during a test with a faulty statement.
  581. return result;
  582. }*/
  583. // discord-connector
  584. DiscordSendChannelMessage(DCC_Channel:channel, const message[]){
  585. if(scriptDebug){ // Log middle-ware event in debugging mode only
  586. new channel_name[100 + 1]; // Default value from tutorial
  587. DCC_GetChannelName(channel, channel_name);
  588. new logMessage[26 + 100 + 2000 + 1]; // Discord max message length = 2000
  589. format(logMessage, sizeof(logMessage), "Send to discord channel %s: %s", channel_name, message);
  590. logger(LOGLEVEL_DEBUG, logMessage); // Actually log the message
  591. }
  592. DCC_SendChannelMessage(channel, message); // Call discord-connector DISABLE THIS TO STOP ALL OUTGOING DISCORD MESSAGES
  593. }
  594. /// Game-mode
  595. // Account functions
  596. forward changeName(playerid, const name[]);
  597. public changeName(playerid, const name[]){ // Check if name is valid and force change if needed.
  598. // Prevent regex error when comparing against null
  599. if(isempty(name)){ // No name entered
  600. ShowPlayerDialog(playerid, DIALOG_CHANGENAME, DIALOG_STYLE_INPUT, "Character name", "You must enter a name.\n\nExamples:\n Jo_Bo\n Dingle_P._J._Berry\n Jackson_DeForest_Kelley\n MaryJo_Ann_LaFluer", "Change", ""); // Force RP name.
  601. return 0;
  602. }
  603. // Check name
  604. new Regex:r = Regex_New("^[A-Z][a-z]{1,}([A-Z][a-z]{1,})?(_([A-Z][a-z]{1,}([A-Z][a-z]{1,})?|[A-Z]\\.(_[A-Z]\\.)?))?_[A-Z][a-z]{1,}([A-Z][a-z]{1,})?$"); // Regex name filter
  605. new isValidName = Regex_Check(name, r); // Validate name to filter
  606. Regex_Delete(r);
  607. if(!isValidName){ // Invalid role-play name
  608. ShowPlayerDialog(playerid, DIALOG_CHANGENAME, DIALOG_STYLE_INPUT, "Character name", "Please pick a realistic name, separate first and last name with an underscore.\n\nExamples:\n Jo_Bo\n Dingle_P._J._Berry\n Jackson_DeForest_Kelley\n MaryJo_Ann_LaFluer", "Change", ""); // Force RP name.
  609. }
  610. else { // Valid role-play name
  611. // Check for name in use
  612. /*new escaped_name[MAX_PLAYER_NAME + 1]; // TODO should be more, to account for escape characters.
  613. sql_escape_string(sqlHandle, name, escaped_name, sizeof(escaped_name)); // Escape player name BROKEN argument type mismatch on argument 2, but name is a sting...*/
  614. new character_query[40 + MAX_PLAYER_NAME + 1], Result:character_result = sql_query(sqlHandle, character_query);
  615. format(character_query, sizeof(character_query), "SELECT id FROM character WHERE name = '%s'", name);
  616. if(sql_num_rows(character_result) > 0){ // Name taken
  617. ShowPlayerDialog(playerid, DIALOG_CHANGENAME, DIALOG_STYLE_INPUT, "Character name", "Name already taken. Please pick an original name.", "Change", ""); // Force RP name.
  618. }
  619. else{ // Name free
  620. // Notify all players
  621. new message[11 + 4 + MAX_PLAYER_NAME + 1];
  622. format(message, sizeof(message), "* [%i] %s joined.", playerid, getCharacterName(playerid));
  623. SendClientMessageToAll(COLOR_NOTICE, message); // Notify all players
  624. DiscordEcho(message, ECHO_CHANNEL); // Notify discord public echo
  625. new client_connect_username[MAX_PLAYER_NAME + 1], admin_message[38 + 4 + MAX_PLAYER_NAME + MAX_PLAYER_NAME + 1];
  626. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid); // Get client connect name
  627. if(GetPlayerState(playerid) == PLAYER_STATE_NONE){ // Not spawned: character creation (Creating a character without registering)
  628. // Notify admins
  629. format(admin_message, sizeof(admin_message), "* [%i] %s temporary charcter, created by: %s", playerid, getCharacterName(playerid), client_connect_username);
  630. sendToAdmins(COLOR_NOTICE, admin_message);
  631. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  632. // Do nothing let continue to spawn, after spawn character will be saved to database.
  633. }
  634. else{ // Spawnedplayer: Creating permanent or renaming an existing permanent character
  635. // Notify admins
  636. format(admin_message, sizeof(admin_message), "* [%i] %s created by: %s", playerid, getCharacterName(playerid), client_connect_username);
  637. sendToAdmins(COLOR_NOTICE, admin_message);
  638. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  639. // Send to skin selection
  640. ForceClassSelection(playerid);
  641. TogglePlayerSpectating(playerid, true);
  642. TogglePlayerSpectating(playerid, false);
  643. }
  644. // Change name (No way yet to change name ingame)
  645. /*if(GetGVarInt("userlevel", playerid) > 1){ // Registered player.
  646. // Get username
  647. new username[MAX_PLAYER_NAME + 1], message[75 + MAX_PLAYER_NAME + 1];
  648. GetGVarString("username", username, sizeof(username), playerid);
  649. // Update or create character name in database
  650. new callback[1];
  651. new Result:result;
  652. new query[51 + MAX_PLAYER_NAME + MAX_PLAYER_NAME + 1];
  653. format(query, sizeof(query), "UPDATE \"user\"(name) VALUES('%s') WHERE username == '%s'", name, username);
  654. sql_wait(sqlHandle); // Wait for other queries to finish
  655. result = sql_query(sqlHandle, query, callback = "", "r");
  656. // Inform user
  657. format(message, sizeof(message), "SERVER: Your username remains unchanged, next time connect as: %s", client_connect_username);
  658. SendClientMessage(playerid, COLOR_WHITE, message);
  659. }*/
  660. SetPlayerName(playerid, name); // Change name in-game
  661. }
  662. }
  663. return 0;
  664. }
  665. forward register(playerid);
  666. public register(playerid){ // Register player in database
  667. if(GetPlayerState(playerid) == PLAYER_STATE_NONE){ // Not spawned
  668. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "ERROR: You need to have spawned to register.");
  669. }
  670. else{ // Spawned player
  671. if(GetGVarInt("userlevel", playerid) != UNREGISTERED_PLAYER){ // Registered player.
  672. new message[35 + MAX_PLAYER_NAME + 1];
  673. format(message, sizeof(message), "ERROR: You are already registered"); //, %s.",
  674. SendClientMessage(playerid, COLOR_WHITE, message);
  675. }
  676. else{ // Unregistered player.
  677. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Password", "Please pick a strong and safe password, that you are able to remember.", "Continue", "Cancel"); // Password prompt
  678. }
  679. }
  680. }
  681. forward createCharacterRecord(playerid, id);
  682. public createCharacterRecord(playerid, id){
  683. new character_query[94 + MAX_SQL_INTEGER + MAX_PLAYER_NAME + 3 + 1];
  684. format(character_query, sizeof(character_query), "INSERT INTO character(user_id, name, skin_id) VALUES(%i, '%s', %i)", id, getPlayerName(playerid), GetPlayerSkin(playerid));
  685. sql_query(sqlHandle, character_query);
  686. }
  687. forward authenticate(playerid);
  688. public authenticate(playerid){
  689. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Sign in", "Enter your password to log on", "Log in", "Cancel"); // Show password confirmation dialog
  690. }
  691. forward characterSelection(playerid);
  692. public characterSelection(playerid){
  693. if(GetGVarInt("userlevel", playerid) < REGISTERED_PLAYER){ // Unregistered player (Or worse?)
  694. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Register first with: /my account register");
  695. }
  696. else{ // Registered player
  697. // If spawned, save current character
  698. if(GetPlayerState(playerid) != PLAYER_STATE_NONE){
  699. savePlayerState(playerid);
  700. }
  701. new id = getUserID(playerid);
  702. new character_query[75 + MAX_SQL_INTEGER + MAX_CHARACTERS_PER_USER_DIGITS + 1];
  703. format(character_query, sizeof(character_query), "SELECT id, name FROM character WHERE user_id = %i LIMIT %i", id, MAX_CHARACTERS_PER_USER);
  704. new Result:character_result = sql_query(sqlHandle, character_query);
  705. new character_string[(MAX_PLAYER_NAME * MAX_CHARACTERS_PER_USER) + 1], character_array[MAX_CHARACTERS_PER_USER + 1];
  706. for(new i = 0; i < sql_num_rows(character_result); i++){
  707. new name[MAX_PLAYER_NAME + 1];
  708. sql_get_field_assoc_ex(character_result, i, "name", name, sizeof(name));
  709. format(character_string, sizeof(character_string), "%s%s\n", character_string, name);
  710. character_array[i] = sql_get_field_assoc_int_ex(character_result, i, "id");
  711. printf("Character ID from array: %i", character_array[i]);
  712. }
  713. new character_array_string[MAX_CHARACTERS_PER_USER * MAX_SQL_INTEGER + 1];
  714. strfrombin(character_array_string, character_array); // Convert array to string for use with GVar
  715. SetGVarString("character_array_string", character_array_string, playerid);
  716. ShowPlayerDialog(playerid, DIALOG_CHARACTERS, DIALOG_STYLE_LIST, "Characters", character_string, "Spawn", "New");
  717. }
  718. }
  719. forward savePlayerState(playerid);
  720. public savePlayerState(playerid){
  721. new escaped_playername[MAX_PLAYER_NAME + 1], character_query[210 + MAX_SQL_INTEGER + 3 + 3 + 1 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_PLAYER_NAME + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1]; // Should be longer to allow for escaped characters
  722. sql_escape_string(sqlHandle, getPlayerName(playerid), escaped_playername, sizeof(escaped_playername)); // Escape player name
  723. new Float:health, Float:armour, Float:x, Float:y, Float:z, Float:Angle;
  724. // Unrealiable TODO change to gvars
  725. GetPlayerHealth(playerid, health);
  726. GetPlayerArmour(playerid, armour);
  727. GetPlayerPos(playerid, x, y, z);
  728. GetPlayerFacingAngle(playerid, Angle);
  729. new world_id = GetPlayerVirtualWorld(playerid);
  730. new interior_id = GetPlayerInterior(playerid);
  731. format(character_query, sizeof(character_query), "UPDATE character SET (cash, health, armour, jailed, pos_x, pos_y, pos_z, rotation, world_id, interior_id) = (%i, '%f', '%f', %i, '%f', '%f', '%f', '%f', %i, %i) WHERE name = '%s'", GetPlayerMoney(playerid), health, armour, 0, x, y, z, Angle, world_id, interior_id, escaped_playername);
  732. sql_query(sqlHandle, character_query);
  733. }
  734. forward kickPlayerDelay(playerid);
  735. public kickPlayerDelay(playerid){
  736. Kick(playerid);
  737. }
  738. forward kickPlayer(playerid, kickerid, const reason[], banned);
  739. public kickPlayer(playerid, kickerid, const reason[], banned){ // Kick a player
  740. // Issuer of kick
  741. new kickername[MAX_PLAYER_NAME + 1], kicker_id[MAX_SQL_INTEGER + 1];
  742. if(kickerid == -1){ // Not kicked by in-game player
  743. kickername = "SERVER";
  744. kicker_id = "NULL";
  745. }
  746. else{ // Kicked by in-game player
  747. kickername = getPlayerName(playerid);
  748. kicker_id = "%s", getUserID(kickerid);
  749. }
  750. strreplace(kickername, "_", " ");
  751. // Action
  752. new action[16 + MAX_SQL_INTEGER + 1];
  753. if(banned){
  754. if(banned < 1){ // Permanent ban
  755. action = "banned permanently";
  756. }
  757. else{ // Temporary ban
  758. format(action, sizeof(action), "banned for %i days", banned);
  759. }
  760. }
  761. else{
  762. action = "kicked";
  763. }
  764. // Notify all players
  765. new playername[MAX_PLAYER_NAME + 1], message[16 + 4 + MAX_PLAYER_NAME + MAX_PLAYER_NAME + 16 + MAX_SQL_REASON + 1], admin_message[23 + 4 + MAX_PLAYER_NAME + 16 + MAX_PLAYER_NAME + MAX_SQL_REASON + 1]; // Max samp chat message length 128 - 8 for "/kick ? ".
  766. GetPlayerName(playerid, playername, sizeof(playername));
  767. format(message, sizeof(message), "* [%i] %s %s, reason: %s", playerid, getCharacterName(playerid), action, reason);
  768. format(admin_message, sizeof(admin_message), "* [%i] %s kicked %s, reason: %s", kickerid, kickername, getCharacterName(playerid), action, reason);
  769. logger(LOGLEVEL_INFO, message); // Log event
  770. SendClientMessageToAll(COLOR_NOTICE, message);
  771. DiscordEcho(message, ECHO_CHANNEL);
  772. sendToAdmins(COLOR_NOTICE, admin_message);
  773. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  774. // Inform player (Redundant, but some people are blind or stupid)
  775. new player_message[30 + 6 + MAX_PLAYER_NAME + MAX_SQL_REASON + 1]; // Max samp chat message length 128 - 8 for "/kick ? ".
  776. format(player_message, sizeof(player_message), "SERVER: You have been %s, reason: %s", action, reason);
  777. SendClientMessage(playerid, COLOR_ERROR, player_message); // Notify player
  778. if(banned){
  779. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "You may appeal this ban via the forum or Discord.");
  780. }
  781. new ip_id = getIPID(playerid);
  782. // Crearte IP kick record
  783. new ip_query[61 + 4 + MAX_SQL_REASON + 4 + 1];
  784. format(ip_query, sizeof(ip_query), "INSERT INTO ip_kick(ip_id, reason, kicker_id) VALUES(%i, '%s', %s)", ip_id, reason, kicker_id);
  785. sql_query(sqlHandle, ip_query);
  786. // Get IP kick record
  787. new ip_id_query[64 + 4 + MAX_SQL_REASON + 4 + 1];
  788. format(ip_id_query, sizeof(ip_id_query), "SELECT id FROM ip_kick WHERE ip_id = %i ORDER BY id DESC LIMIT 1", ip_id);
  789. new Result:ip_id_result = sql_query(sqlHandle, ip_id_query);
  790. new ip_kick_id = sql_get_field_assoc_int(Result:ip_id_result, "id");
  791. // User kick record
  792. printf("Userlevel: %i", GetGVarInt("userlevel", playerid));
  793. if(GetGVarInt("userlevel", playerid) > UNREGISTERED_PLAYER){ // Not logged in to a user account
  794. new user_query[79 + 4 + MAX_SQL_REASON + 4 + 1];
  795. format(user_query, sizeof(user_query), "INSERT INTO user_kick(user_id, reason, kicker_id, ip_kick_id) VALUES(%i, '%s', %s, %i)", getUserID(playerid), reason, kicker_id, ip_kick_id);
  796. sql_query(sqlHandle, user_query);
  797. }
  798. SetTimerEx("kickPlayerDelay", 50, false, "i", playerid); // Give the message 50 milliseconds to reach the player before kicking.
  799. }
  800. banExpiration(days);
  801. banExpiration(days){
  802. if(days < 1){ // Permanent ban
  803. new foo[MAX_SQL_TIMESTAMP + 1] = "0";
  804. return foo;
  805. }
  806. else{ // Temporary ban
  807. new year, month, day, hour, minute, second, expires[MAX_SQL_TIMESTAMP + 1];
  808. getdate(year, month, day);
  809. gettime(hour, minute, second);
  810. day = day + days;
  811. format(expires, sizeof(expires), "%i-%i-%i %i:%i:%i", year, month, day, hour, minute, second);
  812. return expires;
  813. //return year, month, day, hour, minute, second;
  814. //return 0;
  815. }
  816. }
  817. forward banPlayer(playerid, bannerid, const reason[], days);
  818. public banPlayer(playerid, bannerid, const reason[], days){ // Ban & kick a player
  819. new ip_id = getIPID(playerid);
  820. // Create IP ban record
  821. new banner_id, ip_query[72 + MAX_SQL_INTEGER + MAX_SQL_TIMESTAMP + MAX_SQL_REASON + MAX_SQL_INTEGER + 1];
  822. if(bannerid < 0){ // Not banned by in-game player
  823. format(ip_query, sizeof(ip_query), "INSERT INTO ip_ban(ip_id, expires, reason) VALUES(%i, '%s', '%s')", ip_id, banExpiration(days), reason);
  824. }
  825. else{ // Banned by in-game player
  826. banner_id = getUserID(bannerid);
  827. format(ip_query, sizeof(ip_query), "INSERT INTO ip_ban(ip_id, expires, reason, banner_id) VALUES(%i, '%s', '%s', %i)", ip_id, banExpiration(days), reason, banner_id);
  828. }
  829. sql_query(sqlHandle, ip_query);
  830. // Get IP ban record ID
  831. new ban_id_query[61 + MAX_PLAYER_NAME + 1];
  832. format(ban_id_query, sizeof(ban_id_query), "SELECT id FROM ip_ban WHERE ip_id = %i ORDER BY id DESC LIMIT 1", ip_id);
  833. new Result:ban_id_result = sql_query(sqlHandle, ban_id_query);
  834. new ip_ban_id = sql_get_field_assoc_int(ban_id_result, "id");
  835. // User ban record (As banned players get only kicked, noneed to check for active ban)
  836. if(GetGVarInt("userlevel", playerid) > 1){ // Registered player
  837. new user_query[97 + MAX_SQL_INTEGER + MAX_SQL_TIMESTAMP + MAX_SQL_REASON + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  838. format(user_query, sizeof(user_query), "INSERT INTO user_ban(user_id, expires, reason, banner_id, ip_ban_id) VALUES(%i, %s, %s, %i, %i) WHERE id = %i", ip_id, banExpiration(days), reason, banner_id, ip_ban_id);
  839. sql_query(sqlHandle, user_query);
  840. }
  841. // Kick player
  842. kickPlayer(playerid, bannerid, reason, days);
  843. }
  844. // Database functions
  845. forward getIPID(playerid);
  846. public getIPID(playerid){
  847. new player_ip[MAX_SQL_IP + 1], query[37 + MAX_SQL_IP + 1]; // Create varaibles
  848. GetPlayerIp(playerid, player_ip, sizeof(player_ip)); // Polulate player_ip variable
  849. format(query, sizeof(query), "SELECT id FROM ip WHERE address = '%s'", player_ip); // Format query string
  850. new Result:result = sql_query(sqlHandle, query); // Execute query
  851. return sql_get_field_assoc_int(result, "id"); // Get id from result
  852. }
  853. forward getUserID(playerid);
  854. public getUserID(playerid){
  855. // SQL escape username
  856. new client_connect_username[MAX_PLAYER_NAME + 1], escaped_username[MAX_PLAYER_NAME + 1]; // TODO escaped_username should be longer to account for escape characters (Also increate database column size!)
  857. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid); // Get client connect name
  858. sql_escape_string(sqlHandle, client_connect_username, escaped_username, sizeof(escaped_username)); // Escape player name
  859. // Get user ID
  860. new userid_query[47 + MAX_PLAYER_NAME + 1];
  861. format(userid_query, sizeof(userid_query), "SELECT id FROM \"user\" WHERE name = '%s'", escaped_username);
  862. new Result:result = sql_query(sqlHandle, userid_query);
  863. return sql_get_field_assoc_int(result, "id");
  864. }
  865. // Player functions
  866. forward deleteAllGVars(playerid);
  867. public deleteAllGVars(playerid){ // Delete GVars as per https://forum.sa-mp.com/showthread.php?t=151076
  868. DeleteGVar("client_connect_username", playerid); // From OnPlayerConnect()
  869. DeleteGVar("userlevel", playerid); // From OnPlayerConnect()
  870. DeleteGVar("hash", playerid); // From DIALOG_REGISTER
  871. DeleteGVar("character_array_string", playerid); // From OnDialogResponse()
  872. DeleteGVar("authentication_count", playerid); // From DIALOG_LOGIN
  873. DeleteGVar("character_id", playerid); // From DIALOG_CHARACTERS
  874. DeleteGVar("chatmode", playerid); // From cmd:my()
  875. DeleteGVar("disable_pickups", playerid); // From OnPlayerPickUpDynamicPickup()
  876. DeleteGVar("goto_target", playerid); // From cmd:my() & cmd:p()
  877. DeleteGVar("job", playerid); // From OnDialogResponse()
  878. }
  879. getPlayerName(playerid);
  880. getPlayerName(playerid){
  881. // new playername[MAX_PLAYER_NAME + 1];
  882. new const playername[MAX_PLAYER_NAME + 1];
  883. GetPlayerName(playerid, playername, sizeof(playername));
  884. // new output[MAX_PLAYER_NAME + 1];
  885. // strfromliteral(output, playername);
  886. return playername;
  887. }
  888. forward teleportPlayer(playerid, Float:x, Float:y, Float:z, world, interior, Float:angle, const name[]);
  889. public teleportPlayer(playerid, Float:x, Float:y, Float:z, world, interior, Float:angle, const name[]){
  890. SetPlayerPos(playerid, x, y, z);
  891. SetPlayerVirtualWorld(playerid, world);
  892. SetPlayerInterior(playerid, interior);
  893. SetPlayerFacingAngle(playerid, angle);
  894. // Inform admins
  895. new admin_message[21 + 4 + MAX_PLAYER_NAME + 5 + 4 + MAX_PLAYER_NAME + 1 + 1]; // 5 + 4 + MAX_PLAYER_NAME + 1 = name
  896. format(admin_message, sizeof(admin_message), "* [%i] %s teleported to: %s", playerid, getCharacterName(playerid), name);
  897. sendToAdmins(COLOR_NOTICE, admin_message);
  898. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  899. }
  900. forward setPlayerSkin(playerid, skinid);
  901. public setPlayerSkin(playerid, skinid){
  902. print("Called setPlayerSkin()");
  903. new
  904. Float:tmpPos[4],
  905. vehicleid = GetPlayerVehicleID(playerid),
  906. seatid = GetPlayerVehicleSeat(playerid);
  907. GetPlayerPos(playerid, tmpPos[0], tmpPos[1], tmpPos[2]);
  908. GetPlayerFacingAngle(playerid, tmpPos[3]);
  909. if(skinid < 0 || skinid > 299) return 0;
  910. if(GetPlayerSpecialAction(playerid) == SPECIAL_ACTION_DUCK)
  911. {
  912. SetPlayerPos(playerid, tmpPos[0], tmpPos[1], tmpPos[2]);
  913. SetPlayerFacingAngle(playerid, tmpPos[3]);
  914. TogglePlayerControllable(playerid, 1); // preventing any freeze - optional
  915. return SetPlayerSkin(playerid, skinid);
  916. }
  917. else if(IsPlayerInAnyVehicle(playerid))
  918. {
  919. new
  920. tmp;
  921. RemovePlayerFromVehicle(playerid);
  922. SetPlayerPos(playerid, tmpPos[0], tmpPos[1], tmpPos[2]);
  923. SetPlayerFacingAngle(playerid, tmpPos[3]);
  924. TogglePlayerControllable(playerid, 1); // preventing any freeze - important - because of doing animations of exiting vehicle
  925. tmp = SetPlayerSkin(playerid, skinid);
  926. PutPlayerInVehicle(playerid, vehicleid, (seatid == 128) ? 0 : seatid);
  927. return tmp;
  928. }
  929. else
  930. {
  931. return SetPlayerSkin(playerid, skinid);
  932. }
  933. }
  934. // Chat functions
  935. getCharacterName(playerid);
  936. getCharacterName(playerid){ // Convert name from player name
  937. new playername[MAX_PLAYER_NAME + 1], output[MAX_PLAYER_NAME + 1];
  938. GetPlayerName(playerid, playername, sizeof(playername));
  939. strfromliteral(output, playername);
  940. strreplace(output, "_", " ");
  941. return output;
  942. }
  943. forward sendToChat(playerid, target, text[128 + 1], receiver_id, DCC_User:author);
  944. public sendToChat(playerid, target, text[128 + 1], receiver_id, DCC_User:author){
  945. strtrim(text); // Trim edge whitespaces
  946. if(isempty(text)){
  947. return 0; // Fail if text is empty
  948. }
  949. new playername[MAX_PLAYER_NAME + 1];
  950. if(playerid < 0){
  951. DCC_GetUserName(author, playername, sizeof(playername));
  952. print("Hit playerid < 0");
  953. print(text);
  954. } // Discord messagge
  955. else{playername = getCharacterName(playerid);}
  956. new chat_format, chat_color, chat_range, chat_userlevel, chat_character[1 + 1], chat_name[13 + 1], discord_channel;
  957. switch(target){
  958. case CHAT_WHISPER:{
  959. chat_format = 2;
  960. chat_range = 3;
  961. chat_name = "whispers";
  962. chat_color = COLOR_COMMAND_OUTPUT;
  963. discord_channel = ADMIN_ECHO_CHANNEL;
  964. }
  965. case CHAT_LOW:{
  966. chat_format = 2;
  967. chat_range = 10;
  968. chat_name = "speaks softly";
  969. chat_color = COLOR_COMMAND_OUTPUT;
  970. discord_channel = ADMIN_ECHO_CHANNEL;
  971. }
  972. case CHAT_LOCAL:{
  973. chat_format = 1;
  974. chat_range = 20;
  975. chat_color = COLOR_COMMAND_OUTPUT;
  976. discord_channel = ADMIN_ECHO_CHANNEL;
  977. }
  978. case CHAT_SHOUT:{
  979. chat_format = 2;
  980. chat_range = 50;
  981. chat_name = "shouts";
  982. chat_color = COLOR_COMMAND_OUTPUT;
  983. discord_channel = ADMIN_ECHO_CHANNEL;
  984. }
  985. case CHAT_ACTION:{
  986. chat_format = 0;
  987. chat_range = 20;
  988. chat_color = COLOR_COMMAND_OUTPUT;
  989. discord_channel = ADMIN_ECHO_CHANNEL;
  990. }
  991. case CHAT_OC:{
  992. chat_format = 3;
  993. chat_range = 20;
  994. chat_character = "'";
  995. chat_name = "OOC";
  996. chat_color = COLOR_COMMAND_OUTPUT;
  997. discord_channel = ADMIN_ECHO_CHANNEL;
  998. }
  999. case CHAT_GLOBAL:{
  1000. chat_format = 3;
  1001. chat_character = "`";
  1002. chat_name = "Global";
  1003. chat_color = COLOR_COMMAND_OUTPUT;
  1004. discord_channel = ECHO_CHANNEL;
  1005. }
  1006. case CHAT_GANG:{
  1007. chat_format = 3;
  1008. chat_character = "~";
  1009. chat_name = "Gang";
  1010. chat_color = COLOR_CREW_CHAT;
  1011. // TODO: Output to gang Discord channel
  1012. discord_channel = ADMIN_ECHO_CHANNEL;
  1013. }
  1014. case CHAT_GANG_OC:{
  1015. chat_format = 3;
  1016. chat_character = "$";
  1017. chat_name = "Gang OC";
  1018. chat_color = COLOR_CREW_CHAT;
  1019. // TODO: Output to gang Discord channel
  1020. discord_channel = ADMIN_ECHO_CHANNEL;
  1021. }
  1022. case CHAT_FACTION:{
  1023. chat_format = 3;
  1024. chat_character = "!";
  1025. chat_name = "Faction";
  1026. chat_color = COLOR_CREW_CHAT;
  1027. // TODO: Output to faction Discord channel
  1028. discord_channel = ADMIN_ECHO_CHANNEL;
  1029. }
  1030. case CHAT_FACTION_OC:{
  1031. chat_format = 3;
  1032. chat_character = "%";
  1033. chat_name = "Faction OC";
  1034. chat_color = COLOR_CREW_CHAT;
  1035. // TODO: Output to faction Discord channel
  1036. discord_channel = ADMIN_ECHO_CHANNEL;
  1037. }
  1038. case CHAT_CREW:{
  1039. chat_format = 3;
  1040. chat_character = "@";
  1041. chat_name = "Crew";
  1042. chat_color = COLOR_CREW_CHAT;
  1043. chat_userlevel = MODERATOR_CREW;
  1044. discord_channel = ADMIN_ECHO_CHANNEL;
  1045. }
  1046. case CHAT_ADMIN:{
  1047. chat_format = 3;
  1048. chat_character = "#";
  1049. chat_name = "Admin";
  1050. chat_color = COLOR_ADMIN_CHAT;
  1051. chat_userlevel = ADMIN_CREW;
  1052. discord_channel = ADMIN_ECHO_CHANNEL;
  1053. }
  1054. case CHAT_MANAGEMENT:{
  1055. chat_format = 3;
  1056. chat_character = "&";
  1057. chat_name = "Management";
  1058. chat_color = COLOR_ADMIN_CHAT;
  1059. chat_userlevel = MANAGEMENT_CREW;
  1060. discord_channel = MANAGEMENT_CHANNEL;
  1061. }
  1062. case CHAT_VIP:{
  1063. chat_format = 3;
  1064. chat_character = "^";
  1065. chat_name = "VIP";
  1066. chat_color = COLOR_VIP_CHAT;
  1067. chat_userlevel = VIP_PLAYER;
  1068. discord_channel = ADMIN_ECHO_CHANNEL;
  1069. //TODO: Add VIP discord channel.
  1070. }
  1071. case CHAT_UNDERCOVER:{
  1072. chat_format = -1;
  1073. chat_character = "*";
  1074. chat_color = COLOR_COMMAND_OUTPUT;
  1075. chat_userlevel = ADMIN_CREW;
  1076. discord_channel = ECHO_CHANNEL;
  1077. }
  1078. case CHAT_PM:{
  1079. chat_format = 3;
  1080. chat_character = ">";
  1081. chat_name = "PM";
  1082. chat_color = COLOR_PM_CHAT;
  1083. discord_channel = ADMIN_ECHO_CHANNEL;
  1084. }
  1085. case CHAT_CALL:{
  1086. chat_format = 3;
  1087. chat_character = "+";
  1088. chat_name = "Call";
  1089. chat_color = COLOR_PM_CHAT;
  1090. discord_channel = ADMIN_ECHO_CHANNEL;
  1091. }
  1092. case CHAT_SMS:{
  1093. chat_format = 3;
  1094. chat_character = "-";
  1095. chat_name = "SMS";
  1096. chat_color = COLOR_PM_CHAT;
  1097. discord_channel = ADMIN_ECHO_CHANNEL;
  1098. }
  1099. case CHAT_RADIO:{
  1100. chat_format = 3;
  1101. chat_character = "=";
  1102. chat_name = "Radio";
  1103. chat_color = COLOR_PM_CHAT;
  1104. discord_channel = ADMIN_ECHO_CHANNEL;
  1105. }
  1106. }
  1107. // Format chat message
  1108. new message[9 + sizeof(chat_character) + (6 * 8) + sizeof(chat_name) + 4 + MAX_PLAYER_NAME + 128 + 1];
  1109. new discord_message[23 + sizeof(chat_character) + sizeof(chat_name) + sizeof(playerid) + MAX_PLAYER_NAME + 128 + 1];
  1110. switch(chat_format){
  1111. case -1:{
  1112. format(message, sizeof(message), "%s %s", chat_character, text);
  1113. format(discord_message, sizeof(discord_message), "```css\n%s %s\n```", chat_character, text);
  1114. }
  1115. case 0:{
  1116. format(message, sizeof(message), EMBED_COLOR_GREY"[{%06x}%i"EMBED_COLOR_GREY"] {%06x}%s{%06x} %s", GetPlayerColor(playerid) >>> 8, playerid, GetPlayerColor(playerid) >>> 8, playername, chat_color >>> 8, text);
  1117. format(discord_message, sizeof(discord_message), "```css\n[%i] %s %s\n```", playerid, playername, text);
  1118. }
  1119. case 1:{
  1120. format(message, sizeof(message), EMBED_COLOR_GREY"[{%06x}%i"EMBED_COLOR_GREY"] {%06x}%s"EMBED_COLOR_GREY":{%06x} %s", GetPlayerColor(playerid) >>> 8, playerid, GetPlayerColor(playerid) >>> 8, playername, chat_color >>> 8, text);
  1121. format(discord_message, sizeof(discord_message), "```css\n[%i] %s: %s\n```", playerid, playername, text);
  1122. }
  1123. case 2:{
  1124. format(message, sizeof(message), EMBED_COLOR_GREY"[{%06x}%i"EMBED_COLOR_GREY"] {%06x}%s %s"EMBED_COLOR_GREY":{%06x} %s", GetPlayerColor(playerid) >>> 8, playerid, GetPlayerColor(playerid) >>> 8, playername, chat_name, chat_color >>> 8, text);
  1125. format(discord_message, sizeof(discord_message), "```css\n[%i] %s %s: %s\n```", playerid, playername, chat_name, text);
  1126. }
  1127. case 3:{
  1128. format(message, sizeof(message), "%s "EMBED_COLOR_GREY"({%06x}%s"EMBED_COLOR_GREY") [{%06x}%i"EMBED_COLOR_GREY"] {%06x}%s"EMBED_COLOR_GREY":{%06x} %s", chat_character, chat_color >>> 8, chat_name, GetPlayerColor(playerid) >>> 8, playerid, GetPlayerColor(playerid) >>> 8, playername, chat_color >>> 8, text);
  1129. format(discord_message, sizeof(discord_message), "```css\n%s (%s) [%i] %s: %s\n```", chat_character, chat_name, playerid, playername, text);
  1130. }// Good discord tag options for color effects: yaml, css, moon, elixir, haxe, groovy, brainfuck, accesslog,inform7, c,
  1131. }
  1132. // Authorisation
  1133. if(chat_userlevel && chat_userlevel > GetGVarInt("userlevel", playerid)){ // User not privilged to read chat
  1134. if(target == CHAT_CREW){ // Show the user the message was sent to crew chat.
  1135. SendClientMessage(playerid, chat_color, message);
  1136. }
  1137. else{
  1138. SendClientMessage(playerid, COLOR_CREW_CHAT, "ERROR: You are not authorized to speak in this chat.");
  1139. return 0; // Fail to send the message
  1140. }
  1141. }
  1142. // Send TODO: Add checks for muted.
  1143. if(chat_range){ // Ranged chats
  1144. logger(LOGLEVEL_CHAT, message); // Log event
  1145. // Show message to players in range
  1146. new Float:x, Float:y, Float:z;
  1147. GetPlayerPos(playerid, x, y, z);
  1148. for(new recipient_id, a = GetMaxPlayers(); recipient_id < a; recipient_id++){
  1149. if(IsPlayerConnected(receiver_id)){
  1150. new Float:distance = GetPlayerDistanceFromPoint(recipient_id, x, y, z);
  1151. if(distance <= chat_range){ // Player nearby
  1152. sendClientMultiMessage(recipient_id, chat_color, message, Bool:false);
  1153. }
  1154. }
  1155. }
  1156. DiscordEcho(discord_message, discord_channel);
  1157. }
  1158. else{ // Global chats
  1159. if(target == CHAT_GLOBAL){ // Public chat
  1160. logger(LOGLEVEL_CHAT, message); // Log event
  1161. sendClientMultiMessage(0, chat_color, message, Bool:true);
  1162. DiscordEcho(discord_message, discord_channel);
  1163. }
  1164. else if(target == CHAT_GANG || target == CHAT_GANG_OC || target == CHAT_FACTION || target == CHAT_FACTION_OC || target == CHAT_CALL || target == CHAT_SMS || target == CHAT_RADIO ){
  1165. // TODO
  1166. // TODO sendToAdmins();
  1167. // TODO send to specific discord channel
  1168. SendClientMessage(playerid, chat_color, "You are not a member of the required entity.");
  1169. }
  1170. else if(target == CHAT_PM){
  1171. new output[sizeof(message)];
  1172. strdel(message, 0, 1);
  1173. format(output, sizeof(output), "<%s", message);
  1174. sendClientMultiMessage(receiver_id, chat_color, output, Bool:false);
  1175. new receipt[12 + 1 + sizeof(chat_name) + 4 + MAX_PLAYER_NAME + 128 + 1];
  1176. format(receipt, sizeof(receipt), "%s (%s) to [%i] %s: %s", chat_character, chat_name, receiver_id, playername, text);
  1177. sendClientMultiMessage(playerid, chat_color, receipt, Bool:false);
  1178. new admin_message[15 + 1 + sizeof(chat_name) + 4 + MAX_PLAYER_NAME + 4 + 128 + 1];
  1179. format(admin_message, sizeof(admin_message), "%s (%s) [%i] %s to [%i]: %s", chat_character, chat_name, playerid, playername, receiver_id, text);
  1180. logger(LOGLEVEL_CHAT, admin_message); // Log event
  1181. sendToAdmins(chat_color, admin_message);
  1182. DiscordEcho(discord_message, discord_channel);
  1183. }
  1184. else{ // Chat with select users
  1185. for(new recipient_id, a = GetMaxPlayers(); recipient_id < a; recipient_id++){
  1186. if(IsPlayerConnected(recipient_id)){
  1187. if(GetGVarInt("userlevel", recipient_id) >= chat_userlevel){ // Privileged
  1188. logger(LOGLEVEL_CHAT, message); // Log event
  1189. sendClientMultiMessage(recipient_id, chat_color, message, Bool:false);
  1190. DiscordEcho(discord_message, discord_channel);
  1191. }
  1192. }
  1193. }
  1194. }
  1195. }
  1196. return 1;
  1197. }
  1198. forward sendToAdmins(chat_color, const message[]);
  1199. public sendToAdmins(chat_color, const message[]){
  1200. for(new recipient_id, a = GetMaxPlayers(); recipient_id < a; recipient_id++){
  1201. if(IsPlayerConnected(recipient_id)){
  1202. if(GetGVarInt("userlevel", recipient_id) >= ADMIN_CREW){ // Privileged
  1203. SendClientMessage(recipient_id, chat_color, message);
  1204. }
  1205. }
  1206. }
  1207. }
  1208. forward sendPM(playerid, text[128 + 1], recipient_id);
  1209. public sendPM(playerid, text[128 + 1], recipient_id){
  1210. if (recipient_id == INVALID_PLAYER_ID){
  1211. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "ERROR: Player not found.");
  1212. }
  1213. else{
  1214. sendToChat(playerid, CHAT_PM, text, recipient_id, DCC_INVALID_USER);
  1215. // Todo: Send to admins and admin echo
  1216. }
  1217. }
  1218. forward sendClientMultiMessage(recipient_id, chat_color, const message[], Bool:toall);
  1219. public sendClientMultiMessage(recipient_id, chat_color, const message[], Bool:toall){
  1220. if(strlen(message) > 144){ // SAMP does not send messages longer than 144 characters
  1221. new part_1[144 + 1], part_2[144 + 1];
  1222. strmid(part_1, message, 0, 143); // TODO see if this can be moved 1 bit
  1223. strmid(part_2, message, 143, 286);
  1224. if(toall){
  1225. SendClientMessageToAll(chat_color, part_1);
  1226. SendClientMessageToAll(chat_color, part_2);
  1227. }
  1228. else{
  1229. SendClientMessage(recipient_id, chat_color, part_1);
  1230. SendClientMessage(recipient_id, chat_color, part_2);
  1231. }
  1232. }
  1233. else{
  1234. if(toall){SendClientMessageToAll(chat_color, message);}
  1235. else{SendClientMessage(recipient_id, chat_color, message);}
  1236. }
  1237. }
  1238. // Pickup functions
  1239. forward createDynamicPickup(object, Float:x, Float:y, Float:z, world, interior, pickup_type);
  1240. public createDynamicPickup(object, Float:x, Float:y, Float:z, world, interior, pickup_type){
  1241. // Object position corrections
  1242. if(object == 19902){
  1243. z = z - 0.5;
  1244. }
  1245. else if(object == 19607){
  1246. z = z - 0.5;
  1247. }
  1248. // Pickup types
  1249. new type;
  1250. switch(pickup_type){
  1251. case 99999: type = 2;
  1252. default: type = 1;
  1253. }
  1254. new pickupid = CreateDynamicPickup(object, type, x, y, z, world, interior);
  1255. SetGVarInt("pickup_type", pickup_type, pickupid);
  1256. printf("new pickupid = CreateDynamicPickup(%i, %i, %f, %f, %f, %i, %i);", pickupid, object, type, x, y, z, world, interior);
  1257. return pickupid;
  1258. }
  1259. forward spawnPortal(id, object, Float:pos_x, Float:pos_y, Float:pos_z, world, interior, exit_object, Float:exit_pos_x, Float:exit_pos_y, Float:exit_pos_z, exit_world, exit_interior);
  1260. public spawnPortal(id, object, Float:pos_x, Float:pos_y, Float:pos_z, world, interior, exit_object, Float:exit_pos_x, Float:exit_pos_y, Float:exit_pos_z, exit_world, exit_interior){
  1261. new pickup_id = createDynamicPickup(object, pos_x, pos_y, pos_z, world, interior, PICKUP_PORTAL);
  1262. SetGVarFloat("pickup_x", exit_pos_x, pickup_id);
  1263. SetGVarFloat("pickup_y", exit_pos_y, pickup_id);
  1264. SetGVarFloat("pickup_z", exit_pos_z, pickup_id);
  1265. SetGVarInt("pickup_world", exit_world, pickup_id);
  1266. SetGVarInt("pickup_interior", exit_interior, pickup_id);
  1267. new exit_pickup_id = createDynamicPickup(exit_object, exit_pos_x, exit_pos_y, exit_pos_z, exit_world, exit_interior, PICKUP_PORTAL);
  1268. SetGVarFloat("pickup_x", pos_x, exit_pickup_id);
  1269. SetGVarFloat("pickup_y", pos_y, exit_pickup_id);
  1270. SetGVarFloat("pickup_z", pos_z, exit_pickup_id);
  1271. SetGVarInt("pickup_world", world, exit_pickup_id);
  1272. SetGVarInt("pickup_interior", interior, exit_pickup_id);
  1273. new portal_query[64 + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1274. format(portal_query, sizeof(portal_query), "UPDATE portal SET (pickup_id, exit_pickup_id) = (%i, %i) WHERE id = %i", pickup_id, exit_pickup_id, id);
  1275. sql_query(sqlHandle, portal_query);
  1276. }
  1277. forward destroyPortal(id);
  1278. public destroyPortal(id){
  1279. DestroyDynamicPickup(id);
  1280. DeleteGVar("pickup_type", id);
  1281. DeleteGVar("pickup_x", id);
  1282. DeleteGVar("pickup_y", id);
  1283. DeleteGVar("pickup_z", id);
  1284. DeleteGVar("pickup_world", id);
  1285. DeleteGVar("pickup_interior", id);
  1286. }
  1287. // Command functions
  1288. public OnPlayerCommandPerformed(playerid, cmd[], params[], result, flags){
  1289. if(result == -1){
  1290. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Unknown command.");
  1291. return 0;
  1292. }
  1293. return 1;
  1294. }
  1295. public OnPlayerCommandReceived(playerid, cmd[], params[], flags){
  1296. new userlevel = GetGVarInt("userlevel", playerid);
  1297. if(flags){
  1298. if(flags > userlevel){
  1299. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Access denied.");
  1300. printf("player %d doesn�t have access to command '%s'", playerid, cmd); // TODO decide to send this to a chat or not.
  1301. return 0;
  1302. }
  1303. }
  1304. return 1;
  1305. }
  1306. public PC_OnInit(){ // TODO
  1307. return 1; // Remove this once stuff is in place.
  1308. }
  1309. flags:test(ADMIN_CREW);
  1310. cmd:test(playerid, params[]){
  1311. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Executed");
  1312. return 1;
  1313. }
  1314. // Command commands
  1315. cmd:help(playerid, params[]){
  1316. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Ask questions in the chat, on Discord or the forum.\nTo list all commands: /cmds");
  1317. return 1;
  1318. }
  1319. alias:help("h");
  1320. cmd:cmds(playerid, params[]){
  1321. SendClientMessage(playerid, COLOR_NOTICE, "Command help syntax: \"/\" = start of cmd, \"()\" = cmd aliasses, \"|\" = or, \"<>\" = required parameter, \"[]\" = optional parameter, \",\" = next item.");
  1322. SendClientMessage(playerid, COLOR_NOTICE, "Command help syntax example: /command (/alias | /other_alias) <parameter> [optional_parameter], /next_command");
  1323. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "General commands: /help (/h), /cmds (/cmd | /commands), /my (/myself | /mine), /v (/vehivle | /veh), /p (/player)");
  1324. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Chat commands: /me (/emote | /action), /w (/whisper), /low (/soft), /l (/local), /s (/shout | /scream), /o (' | /oc | /ooc)");
  1325. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Chat commands: /g (` | /global | /public), /gc (~) /fc (!), /vc (&), /cc (@), /my chatmode <value>");
  1326. if(GetGVarInt("userlevel", playerid) >= ADMIN_CREW){
  1327. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Admin commands: /property");
  1328. }
  1329. return 0;
  1330. }
  1331. alias:cmds("commands", "cmd");
  1332. // User commands
  1333. cmd:register(playerid, params[]){
  1334. register(playerid);
  1335. }
  1336. cmd:my(playerid, params[]){
  1337. // No option specified
  1338. if(strlen(params) < 1){
  1339. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /my <option> <value>");
  1340. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Options: account chatmode");
  1341. if(GetGVarInt("userlevel", playerid) >= ADMIN_CREW){
  1342. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Admin options: goto");
  1343. }
  1344. return 0;
  1345. }
  1346. // Options
  1347. if(!strcmp(params, "account", true, 7)){ // /my account
  1348. strdel(params, 0, 8); // Remove first 8 characters, "account ", from the string.
  1349. // Values
  1350. if (isequal(params, "register", .ignorecase = true)){ // /my account register
  1351. register(playerid); // Call public register function
  1352. }
  1353. else if (isequal(params, "characters", .ignorecase = true)){ // /my account characters
  1354. characterSelection(playerid);
  1355. }
  1356. else if (isequal(params, "deletecharacter", .ignorecase = true)){ // /my account characters
  1357. ShowPlayerDialog(playerid, DIALOG_DELETE_CHARACTER, DIALOG_STYLE_MSGBOX, "Charater deletion", "You are about to permanently delete this charater and all it's assets.\n This can NOT be undone.", "Destroy", "Abort");
  1358. }
  1359. else{ // Invalid value
  1360. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /my account <value>");
  1361. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Values: register characters deletecharacter");
  1362. }
  1363. }
  1364. else if(!strcmp(params, "chatmode", true, 8)){ // /my chatmode
  1365. strdel(params, 0, 9); // Remove first 9 characters, "account ", from the string.
  1366. // Values
  1367. if (isequal(params, "whisper", .ignorecase = true)){
  1368. SetGVarInt("chatmode", CHAT_WHISPER, playerid);
  1369. }
  1370. else if (isequal(params, "low", .ignorecase = true)){
  1371. SetGVarInt("chatmode", CHAT_LOW, playerid);
  1372. }
  1373. else if (isequal(params, "local", .ignorecase = true)){
  1374. SetGVarInt("chatmode", CHAT_LOCAL, playerid);
  1375. }
  1376. else if (isequal(params, "shout", .ignorecase = true)){
  1377. SetGVarInt("chatmode", CHAT_SHOUT, playerid);
  1378. }
  1379. else if (isequal(params, "oc", .ignorecase = true)){
  1380. SetGVarInt("chatmode", CHAT_OC, playerid);
  1381. }
  1382. else if (isequal(params, "global", .ignorecase = true)){
  1383. SetGVarInt("chatmode", CHAT_GLOBAL, playerid);
  1384. }
  1385. else if (isequal(params, "gang", .ignorecase = true)){
  1386. SetGVarInt("chatmode", CHAT_GANG, playerid);
  1387. }
  1388. else if (isequal(params, "faction", .ignorecase = true)){
  1389. SetGVarInt("chatmode", CHAT_FACTION, playerid);
  1390. }
  1391. else if (isequal(params, "vip", .ignorecase = true)){
  1392. SetGVarInt("chatmode", CHAT_VIP, playerid);
  1393. }
  1394. else if (isequal(params, "crew", .ignorecase = true)){
  1395. SetGVarInt("chatmode", CHAT_CREW, playerid);
  1396. }
  1397. else if (isequal(params, "admin", .ignorecase = true)){
  1398. SetGVarInt("chatmode", CHAT_ADMIN, playerid);
  1399. }
  1400. else if (isequal(params, "management", .ignorecase = true)){
  1401. SetGVarInt("chatmode", CHAT_MANAGEMENT, playerid);
  1402. }
  1403. else{ // Invalid value
  1404. printf("else isequals register");
  1405. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /my chatmode <value>");
  1406. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Values: whisper low local shout oc global gang faction vip crew admin management");
  1407. }
  1408. }
  1409. else if(!strcmp(params, "goto", true, 4) || !strcmp(params, "sendto", true, 6) || !strcmp(params, "teleport", true, 8)){
  1410. if(GetGVarInt("userlevel", playerid) < ADMIN_CREW){
  1411. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Access denied.");
  1412. }
  1413. SetGVarInt("goto_target", playerid, playerid);
  1414. ShowPlayerDialog(playerid, DIALOG_GOTO, DIALOG_STYLE_LIST, "Categories", "Interiors\nPlayers", "Select", "Cancel");
  1415. }
  1416. else{ // Invalid option
  1417. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/my options: account chatmode");
  1418. if(GetGVarInt("userlevel", playerid) >= ADMIN_CREW){
  1419. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Admin options: goto");
  1420. }
  1421. }
  1422. return 0;
  1423. }
  1424. alias:my("myself", "mine");
  1425. // Chat commands
  1426. cmd:w(playerid, params[128 + 1]){
  1427. sendToChat(playerid, CHAT_WHISPER, params, 0, DCC_INVALID_USER);
  1428. return 1;
  1429. }
  1430. alias:w("whisper");
  1431. cmd:low(playerid, params[128 + 1]){
  1432. sendToChat(playerid, CHAT_LOW, params, 0, DCC_INVALID_USER);
  1433. return 1;
  1434. }
  1435. alias:low("soft");
  1436. cmd:l(playerid, params[128 + 1]){
  1437. sendToChat(playerid, CHAT_LOCAL, params, 0, DCC_INVALID_USER);
  1438. return 1;
  1439. }
  1440. alias:l("local");
  1441. cmd:me(playerid, params[128 + 1]){
  1442. sendToChat(playerid, CHAT_ACTION, params, 0, DCC_INVALID_USER);
  1443. return 1;
  1444. }
  1445. alias:me("emote", "action");
  1446. cmd:s(playerid, params[128 + 1]){
  1447. sendToChat(playerid, CHAT_SHOUT, params, 0, DCC_INVALID_USER);
  1448. return 1;
  1449. }
  1450. alias:s("shout", "scream");
  1451. cmd:o(playerid, params[128 + 1]){
  1452. sendToChat(playerid, CHAT_OC, params, 0, DCC_INVALID_USER);
  1453. return 1;
  1454. }
  1455. alias:o("oc", "ooc");
  1456. cmd:g(playerid, params[128 + 1]){
  1457. sendToChat(playerid, CHAT_GLOBAL, params, 0, DCC_INVALID_USER);
  1458. return 1;
  1459. }
  1460. alias:g("global", "public");
  1461. cmd:gc(playerid, params[128 + 1]){
  1462. sendToChat(playerid, CHAT_GANG, params, 0, DCC_INVALID_USER);
  1463. return 1;
  1464. }
  1465. cmd:fc(playerid, params[128 + 1]){
  1466. sendToChat(playerid, CHAT_FACTION, params, 0, DCC_INVALID_USER);
  1467. return 1;
  1468. }
  1469. cmd:vc(playerid, params[128 + 1]){
  1470. sendToChat(playerid, CHAT_VIP, params, 0, DCC_INVALID_USER);
  1471. return 1;
  1472. }
  1473. cmd:cc(playerid, params[128 + 1]){
  1474. sendToChat(playerid, CHAT_CREW, params, 0, DCC_INVALID_USER);
  1475. return 1;
  1476. }
  1477. cmd:pm(playerid, params[128 + 1]){
  1478. new recipient_id, message[128 + 1];
  1479. if (sscanf(params, "u s", recipient_id, message)){
  1480. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /pm <playerid> <message>");
  1481. }
  1482. else{
  1483. sendPM(playerid, message, recipient_id);
  1484. }
  1485. return 1;
  1486. }
  1487. alias:pm("msg", "dm");
  1488. // Vehicle commands
  1489. cmd:v(playerid, params[]){
  1490. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "health/armor [AMOUNT]");
  1491. return 1;
  1492. }
  1493. alias:v("vehicle", "veh");
  1494. // Player commands
  1495. cmd:p(playerid, params[]){
  1496. // No parameters
  1497. if(strlen(params) < 1){
  1498. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /p <ID> option");
  1499. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/p options: admin, goto");
  1500. }
  1501. // Syntax
  1502. new player_id, option[123 + 1];
  1503. if(sscanf(params, "i s", player_id, option)){
  1504. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /p <ID> <option>");
  1505. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/p options: admin, goto");
  1506. }
  1507. if(!strcmp(option, "admin", true, 5)){
  1508. SetGVarInt("userlevel", ADMIN_CREW, player_id);
  1509. // TODO take admin if already admin
  1510. // TODO notify admins
  1511. }
  1512. else if(!strcmp(option, "goto", true, 4) && !strcmp(option, "sendto", true, 6 && !strcmp(option, "teleport", true, 8)) ){
  1513. if(GetGVarInt("userlevel", playerid) < ADMIN_CREW){
  1514. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: Access denied.");
  1515. SetGVarInt("goto_target", player_id);
  1516. }
  1517. }
  1518. else{
  1519. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/p <ID> options: admin, goto");
  1520. }
  1521. return 1;
  1522. }
  1523. alias:p("player");
  1524. // Admin commands
  1525. flags:property(ADMIN_CREW);
  1526. cmd:property(playerid, params[]){
  1527. // No option specified
  1528. if(strlen(params) < 1){
  1529. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/property options: pickup, portal");
  1530. }
  1531. // Options
  1532. if(!strcmp(params, "pickup", true, 6)){ // /property pickup
  1533. strdel(params, 0, 7); // Remove first 7 characters, "pickup ", from the string.
  1534. // No parameters
  1535. if(strlen(params) < 1){
  1536. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /property pickup <create | ID <goto | move | delete>>");
  1537. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/p options: admin, goto");
  1538. }
  1539. // Values
  1540. new pickup_id, option[110 + 1];
  1541. if(!strcmp(params, "create", true)){ // /property pickup create
  1542. ShowPlayerDialog(playerid, DIALOG_CREATE_PICKUP, DIALOG_STYLE_LIST, "Pickup caterogy", "Faction", "Select", "Cancel");
  1543. }
  1544. else if (!sscanf(params, "i s", pickup_id, option)){
  1545. new pickup_query[62 + MAX_SQL_INTEGER + 1];
  1546. format(pickup_query, sizeof(pickup_query), "SELECT object_id, type_id, pickup_id, pos_x, pos_y, pos_z, world_id, pickup_id FROM pickup WHERE id = %i", pickup_id);
  1547. new Result:pickup_result = sql_query(sqlHandle, pickup_query);
  1548. if(sql_num_rows(pickup_result) < 1){ // Invalid pickup ID
  1549. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Invalid pickup ID");
  1550. }
  1551. new pickupid = sql_get_field_assoc_int(pickup_result, "pickup_id");
  1552. print(option);
  1553. if(!strcmp(option, "move", true)){
  1554. print("move");
  1555. // Destroy old pickup
  1556. DestroyDynamicPickup(pickupid);
  1557. // Create new pickup
  1558. new Float:x, Float:y, Float:z;
  1559. GetPlayerPos(playerid, x, y, z);
  1560. new interior = GetPlayerInterior(playerid);
  1561. new world = GetPlayerVirtualWorld(playerid);
  1562. new object_id = sql_get_field_assoc_int(Result:pickup_result, "object_id");
  1563. new type_id = sql_get_field_assoc_int(Result:pickup_result, "type_id");
  1564. new new_pickupid = createDynamicPickup(object_id, x, y, z, world, interior, type_id);
  1565. // Update pickup record
  1566. new update_query[109 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1567. format(update_query, sizeof(update_query), "UPDATE pickup SET pos_x = '%f', pos_y = '%f', pos_z = '%f', world_id = %i, interior_id = %i, pickup_id = %i WHERE id = %i", x, y, z, world, interior, new_pickupid, pickup_id);
  1568. sql_query(sqlHandle, update_query);
  1569. // Inform admins
  1570. new admin_message[39 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  1571. format(admin_message, sizeof(admin_message), "* [%i] %s modified the location of pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  1572. sendToAdmins(COLOR_NOTICE, admin_message);
  1573. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  1574. }
  1575. else if(!strcmp(option, "delete", true)){
  1576. // Destroy pickup
  1577. DestroyDynamicPickup(pickupid);
  1578. // Delete pickup record
  1579. new update_query[95 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1580. format(update_query, sizeof(update_query), "DELETE FROM pickup WHERE id = %i", pickup_id);
  1581. sql_query(sqlHandle, update_query);
  1582. // Inform admins
  1583. new admin_message[39 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  1584. format(admin_message, sizeof(admin_message), "* [%i] %s deleted pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  1585. sendToAdmins(COLOR_NOTICE, admin_message);
  1586. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  1587. }
  1588. else if(!strcmp(option, "goto", true)){
  1589. SetPlayerPos(playerid, sql_get_field_assoc_int(Result:pickup_result, "pos_x"), sql_get_field_assoc_int(Result:pickup_result, "pos_y"), sql_get_field_assoc_int(Result:pickup_result, "pos_z"));
  1590. SetPlayerVirtualWorld(playerid, sql_get_field_assoc_int(Result:pickup_result, "world_id"));
  1591. SetPlayerInterior(playerid, sql_get_field_assoc_int(Result:pickup_result, "interior_id"));
  1592. }
  1593. else{ // Invalid option.
  1594. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/property pickup <ID> usage: goto, move, delete");
  1595. }
  1596. }
  1597. else{ // Invalid value
  1598. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/property pickup usage: create, <ID> <goto | move | delete>");
  1599. }
  1600. }
  1601. else if(!strcmp(params, "portal", true, 6)){ // /property portal
  1602. strdel(params, 0, 7); // Remove first 7 characters, "portal ", from the string.
  1603. // No parameters
  1604. if(strlen(params) < 1){
  1605. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /property portal <create | ID <goto | exit | entrance | object | delete>>");
  1606. }
  1607. // Values
  1608. new portal_id, option[116 + 1];
  1609. if (!strcmp(params, "create", true, 6)){ // /property portal create
  1610. strdel(params, 0, 7); // Remove first 7 characters, "create ", from the string.
  1611. // Worlds
  1612. new world[105 + 1], world_id;
  1613. if (sscanf(params, "s", world)){
  1614. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "For a portal that works in all worlds use: /property portal create all");
  1615. }
  1616. if(!strcmp(world, "all", true)){
  1617. world_id = -1;
  1618. }
  1619. else{
  1620. world_id = GetPlayerVirtualWorld(playerid);
  1621. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Invalid world option, creating default portal.");
  1622. }
  1623. new Float:x, Float:y, Float:z;
  1624. GetPlayerPos(playerid, x, y, z);
  1625. new interior = GetPlayerInterior(playerid);
  1626. new pickup_id = createDynamicPickup(19902, x, y, z, world_id, interior, PICKUP_PORTAL);
  1627. // Create portal database record
  1628. new portal_query[111 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + 1];
  1629. format(portal_query, sizeof(portal_query), "INSERT INTO portal(object, pos_x, pos_y, pos_z, world, pickup_id, interior_id) VALUES (19902, '%f', '%f', '%f', %i, %i, %i)", x, y, z, world_id, pickup_id, interior);
  1630. sql_query(sqlHandle, portal_query);
  1631. // Inform user(s)
  1632. new portal_id_query[91 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + 1];
  1633. format(portal_id_query, sizeof(portal_id_query), "SELECT id FROM portal WHERE pos_x = '%f' AND pos_y = '%f' AND pos_z = '%f' AND world = %i AND interior_id = %i", x, y, z, world_id, interior);
  1634. new Result:portal_id_result = sql_query(sqlHandle, portal_id_query);
  1635. portal_id = sql_get_field_assoc_int(Result:portal_id_result, "id");
  1636. new message[69 + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1], admin_message[21 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  1637. format(message, sizeof(message), "Portal %i created. Create the other side with: /property portal %i exit", portal_id, portal_id);
  1638. format(admin_message, sizeof(admin_message), "* [%i] %s created portal: %i", playerid, getPlayerName(playerid), portal_id);
  1639. sendToAdmins(COLOR_NOTICE , admin_message);
  1640. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, message);
  1641. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  1642. }
  1643. else if (!sscanf(params, "i s", portal_id, option)){
  1644. // Get portal record
  1645. new portal_query[171 + MAX_SQL_INTEGER + 1];
  1646. format(portal_query, sizeof(portal_query), "SELECT object, pos_x, pos_y, pos_z, world, interior_id, pickup_id, exit_pos_x, exit_pos_y, exit_pos_z, exit_world, exit_interior_id, exit_pickup_id FROM portal WHERE id = %i", portal_id);
  1647. new Result:portal_result = sql_query(sqlHandle, portal_query);
  1648. // Invalid portal ID
  1649. if(sql_num_rows(portal_result) < 1){ // Invalid portal ID
  1650. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Invalid portal ID");
  1651. }
  1652. if (!strcmp(option, "exit", true, 4)){
  1653. new Float:pos_x = sql_get_field_assoc_float(portal_result, "pos_x");
  1654. new Float:pos_y = sql_get_field_assoc_float(portal_result, "pos_y");
  1655. new Float:pos_z = sql_get_field_assoc_float(portal_result, "pos_z");
  1656. new world_id = sql_get_field_assoc_int(portal_result, "world");
  1657. new interior_id = sql_get_field_assoc_int(portal_result, "interior_id");
  1658. new session_id = sql_get_field_assoc_int(portal_result, "pickup_id");
  1659. new exit_pickup_id = sql_get_field_assoc_int(portal_result, "exit_pickup_id");
  1660. // World
  1661. new world;
  1662. if(world_id != -1){ // Not an all-world portal
  1663. world = GetPlayerVirtualWorld(playerid);
  1664. }
  1665. else{
  1666. world = world_id;
  1667. }
  1668. // Location
  1669. new Float:x, Float:y, Float:z;
  1670. GetPlayerPos(playerid, x, y, z);
  1671. new interior = GetPlayerInterior(playerid);
  1672. // Delete old exit if exists
  1673. if(exit_pickup_id){
  1674. destroyPortal(exit_pickup_id);
  1675. }
  1676. new pickup_id = createDynamicPickup(19607, x, y, z, world, interior, PICKUP_PORTAL);
  1677. SetGVarFloat("pickup_x", pos_x, pickup_id);
  1678. SetGVarFloat("pickup_y", pos_y, pickup_id);
  1679. SetGVarFloat("pickup_z", pos_z, pickup_id);
  1680. SetGVarInt("pickup_world", world_id, pickup_id);
  1681. SetGVarInt("pickup_interior", interior_id, pickup_id);
  1682. SetGVarFloat("pickup_x", x, session_id);
  1683. SetGVarFloat("pickup_y", y, session_id);
  1684. SetGVarFloat("pickup_z", z, session_id);
  1685. SetGVarInt("pickup_world", world, session_id);
  1686. SetGVarInt("pickup_interior", interior, session_id);
  1687. // Update portal record
  1688. new update_query[155 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1689. format(update_query, sizeof(update_query), "UPDATE portal SET exit_object = 19607, exit_pos_x = '%f', exit_pos_y = '%f', exit_pos_z = '%f', exit_world = %i, exit_interior_id = %i, exit_pickup_id = %i WHERE id = %i", x, y, z, world, interior, pickup_id, portal_id);
  1690. sql_query(sqlHandle, update_query);
  1691. // Inform admins and Discord
  1692. new admin_message[61 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  1693. format(admin_message, sizeof(admin_message), "* [%i] %s modified the exit location of portal: %i", playerid, getPlayerName(playerid), portal_id);
  1694. sendToAdmins(COLOR_NOTICE , admin_message);
  1695. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  1696. }
  1697. else if(!strcmp(option, "object", true, 6)){
  1698. new object, exit_object;
  1699. if (sscanf(option, "i i", object, exit_object)){
  1700. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Invalid syntax, specify two object ID's: /property portal <ID> object <ID> <ID>");
  1701. }
  1702. new Float:pos_x = sql_get_field_assoc_float(portal_result, "pos_x");
  1703. new Float:pos_y = sql_get_field_assoc_float(portal_result, "pos_y");
  1704. new Float:pos_z = sql_get_field_assoc_float(portal_result, "pos_z");
  1705. new world_id = sql_get_field_assoc_int(portal_result, "world");
  1706. new interior_id = sql_get_field_assoc_int(portal_result, "interior_id");
  1707. new pickup_id = sql_get_field_assoc_int(portal_result, "pickup_id");
  1708. new Float:exit_pos_x = sql_get_field_assoc_float(portal_result, "exit_pos_x");
  1709. new Float:exit_pos_y = sql_get_field_assoc_float(portal_result, "exit_pos_y");
  1710. new Float:exit_pos_z = sql_get_field_assoc_float(portal_result, "exit_pos_z");
  1711. new exit_world_id = sql_get_field_assoc_int(portal_result, "exit_world");
  1712. new exit_interior_id = sql_get_field_assoc_int(portal_result, "exit_interior_id");
  1713. new exit_pickup_id = sql_get_field_assoc_int(portal_result, "exit_pickup_id");
  1714. destroyPortal(exit_pickup_id);
  1715. destroyPortal(pickup_id);
  1716. spawnPortal(portal_id, object, pos_x, pos_y, pos_z, world_id, interior_id, exit_object, exit_pos_x, exit_pos_y, exit_pos_z, exit_world_id, exit_interior_id);
  1717. new update_query[57 + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1718. format(update_query, sizeof(update_query), "UPDATE portal SET (object, exit_object) = (%i, %i) WHERE id = %i", object, exit_object, portal_id);
  1719. sql_query(sqlHandle, portal_query);
  1720. }
  1721. else if(!strcmp(option, "delete", true, 6)){
  1722. new pickup_id = sql_get_field_assoc_int(portal_result, "pickup_id");
  1723. new exit_pickup_id = sql_get_field_assoc_int(portal_result, "exit_pickup_id");
  1724. // TODO: Confirmation, by spectating the pickup or having to be near.
  1725. destroyPortal(exit_pickup_id);
  1726. destroyPortal(pickup_id);
  1727. // Delete portal record
  1728. new delete_query[31 + MAX_SQL_INTEGER + 1];
  1729. format(delete_query, sizeof(delete_query), "DELETE FROM portal WHERE id = %i", portal_id);
  1730. sql_query(sqlHandle, delete_query);
  1731. }
  1732. else if(!strcmp(option, "entrance", true, 8)){
  1733. new object = sql_get_field_assoc_int(portal_result, "object");
  1734. //new Float:x = sql_get_field_assoc_float(portal_result, "pos_x");
  1735. //new Float:y = sql_get_field_assoc_float(portal_result, "pos_y");
  1736. //new Float:z = sql_get_field_assoc_float(portal_result, "pos_z"); todo shorten qeury
  1737. new world = sql_get_field_assoc_int(portal_result, "world");
  1738. new pickup_id = sql_get_field_assoc_int(portal_result, "pickup_id");
  1739. new Float:pos_x = sql_get_field_assoc_float(portal_result, "exit_pos_x");
  1740. new Float:pos_y = sql_get_field_assoc_float(portal_result, "exit_pos_y");
  1741. new Float:pos_z = sql_get_field_assoc_float(portal_result, "exit_pos_z");
  1742. new world_id = sql_get_field_assoc_int(portal_result, "exit_world");
  1743. new interior_id = sql_get_field_assoc_int(portal_result, "exit_interior");
  1744. if(sql_num_rows(portal_result) < 1){ // Invalid portal ID
  1745. return SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Invalid portal ID");
  1746. }
  1747. // World
  1748. if(world_id != -1){ // Not an all-world portal
  1749. world = GetPlayerVirtualWorld(playerid);
  1750. }
  1751. else{
  1752. world = world_id;
  1753. }
  1754. // Location
  1755. new Float:x, Float:y, Float:z;
  1756. GetPlayerPos(playerid, x, y, z);
  1757. new interior = GetPlayerInterior(playerid);
  1758. destroyPortal(pickup_id); // Despawn old pickups and remove GVars
  1759. new pickupid = createDynamicPickup(object, x, y, z, world, interior, PICKUP_PORTAL);
  1760. SetGVarFloat("pickup_x", pos_x, pickupid);
  1761. SetGVarFloat("pickup_y", pos_y, pickupid);
  1762. SetGVarFloat("pickup_z", pos_z, pickupid);
  1763. SetGVarInt("pickup_world", world_id, pickupid);
  1764. SetGVarInt("pickup_interior", interior_id, pickupid);
  1765. // Inform admins and Discord
  1766. new admin_message[65 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  1767. format(admin_message, sizeof(admin_message), "* [%i] %s modified the entrance location of portal: %i", playerid, getPlayerName(playerid), portal_id);
  1768. sendToAdmins(COLOR_NOTICE, admin_message);
  1769. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  1770. }
  1771. else if(!strcmp(option, "goto", true)){
  1772. SetPlayerPos(playerid, sql_get_field_assoc_int(Result:portal_result, "exit_pos_x"), sql_get_field_assoc_int(Result:portal_result, "exit_pos_y"), sql_get_field_assoc_int(Result:portal_result, "exit_pos_z"));
  1773. SetPlayerVirtualWorld(playerid, sql_get_field_assoc_int(Result:portal_result, "exit_world_id"));
  1774. SetPlayerInterior(playerid, sql_get_field_assoc_int(Result:portal_result, "exit_interior_id"));
  1775. }
  1776. else{ // Invalid option
  1777. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/property portal <ID> options: goto, exit, entrance, object, delete");
  1778. }
  1779. }
  1780. else{ // Invalid value
  1781. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: /property portal <create | ID <goto | exit | entrance | object | delete>>");
  1782. }
  1783. }
  1784. else{ // Invalid option
  1785. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "/property options: pickup, portal");
  1786. }
  1787. return 1;
  1788. }
  1789. // Dialog functions
  1790. forward dialogGotoInterior(playerid);
  1791. public dialogGotoInterior(playerid){
  1792. ShowPlayerDialog(playerid, DIALOG_GOTO_INTERIOR, DIALOG_STYLE_LIST, "Categories", "24/7's\nAvaition\nAmmunation's\nBurglary houses\nMissions\nMission exteriors\nMission houses\nModding shops\nPolice departments\nSafe houses\nShops & casino's\nStadia", "Select", "Back");
  1793. }
  1794. forward dialogGotoPlayer(playerid);
  1795. public dialogGotoPlayer(playerid){
  1796. for(new targetid, a = GetMaxPlayers(); targetid < a; targetid++){
  1797. if(IsPlayerConnected(targetid)){
  1798. // TODO: Decide to use this or TABplayer list.
  1799. }
  1800. }
  1801. ShowPlayerDialog(playerid, DIALOG_GOTO_PLAYER, DIALOG_STYLE_LIST, "Players", "", "Goto", "Back");
  1802. }
  1803. // a_samp events
  1804. public OnGameModeInit(){
  1805. new message[36 + 22 + 1];
  1806. format(message, sizeof(message), "* Global game-mode initialization: v%s", MODE_NAME);
  1807. logger(LOGLEVEL_NOTICE, "* Global game-mode initialization."); // Log event.
  1808. // Player radar blip markers only visible to nearby players.
  1809. ShowPlayerMarkers(PLAYER_MARKERS_MODE_STREAMED);
  1810. LimitPlayerMarkerRadius(15);
  1811. // Set mode name
  1812. SetGameModeText(MODE_NAME);
  1813. // SQL log level
  1814. if(scriptDebug){
  1815. sql_debug(LOG_ALL, LOG_ALL); // Log everything everywhere.
  1816. }
  1817. else{
  1818. sql_debug(LOG_INFO, LOG_WARNING); // Loglevel info for file and worning for console.
  1819. }
  1820. // Connect to database
  1821. sqlHandle = SQL:sql_connect(SQL_HANDLER_POSTGRESQL, PG_HOST, PG_ROLE, PG_PASS, PG_DB, PG_PORT);
  1822. printf("sqlconnection = %d", _:sqlHandle);
  1823. if(!sql_ping(sqlHandle)){
  1824. print( " + Database connection" );
  1825. }
  1826. else{
  1827. print( "Database connection failed" );
  1828. }
  1829. // Initialize Discord
  1830. //homeGuild = DCC_GetGuildId(DISCORD_HOME_GUILD_ID); // Set home guild ID. NOT NEEDED FOR NOW AND BROKEN
  1831. echoChannel = DCC_FindChannelById(DISCORD_ECHO_CHANNEL_ID); // Set main echo channel ID.
  1832. mainChannel = DCC_FindChannelById(DISCORD_MAIN_CHANNEL_ID); // Set main notification channel ID.
  1833. adminEchoChannel = DCC_FindChannelById(DISCORD_ADMIN_ECHO_CHANNEL_ID); // Set admin echo channel ID.
  1834. adminChannel = DCC_FindChannelById(DISCORD_ADMIN_CHANNEL_ID); // Set admin notification channel ID.
  1835. managementChannel = DCC_FindChannelById(DISCORD_MANAGEMENT_CHANNEL_ID); // Set management notification channel ID.
  1836. DiscordEcho(message, ECHO_CHANNEL); // Notify Discord
  1837. //DiscordEcho(message, MAIN_CHANNEL); // TODO Enable after we are stable
  1838. // Portals
  1839. new Result:portal_result = sql_query(sqlHandle, "SELECT id, object, pos_x, pos_y, pos_z, world, interior_id, exit_object, exit_pos_x, exit_pos_y, exit_pos_z, exit_world, exit_interior_id FROM portal");
  1840. for(new i = 0; i < sql_num_rows(portal_result); i++){
  1841. new id = sql_get_field_assoc_int_ex(portal_result, i, "id");
  1842. new object = sql_get_field_assoc_int_ex(portal_result, i, "object");
  1843. new Float:pos_x = sql_get_field_assoc_float_ex(portal_result, i, "pos_x");
  1844. new Float:pos_y = sql_get_field_assoc_float_ex(portal_result, i, "pos_y");
  1845. new Float:pos_z = sql_get_field_assoc_float_ex(portal_result, i, "pos_z");
  1846. new world = sql_get_field_assoc_int_ex(portal_result, i, "world");
  1847. new interior = sql_get_field_assoc_int_ex(portal_result, i, "interior_id");
  1848. new exit_object = sql_get_field_assoc_int_ex(portal_result, i, "exit_object");
  1849. new Float:exit_pos_x = sql_get_field_assoc_float_ex(portal_result, i, "exit_pos_x");
  1850. new Float:exit_pos_y = sql_get_field_assoc_float_ex(portal_result, i, "exit_pos_y");
  1851. new Float:exit_pos_z = sql_get_field_assoc_float_ex(portal_result, i, "exit_pos_z");
  1852. new exit_world = sql_get_field_assoc_int_ex(portal_result, i, "exit_world");
  1853. new exit_interior = sql_get_field_assoc_int_ex(portal_result, i, "exit_interior_id");
  1854. spawnPortal(id, object, pos_x, pos_y, pos_z, world, interior, exit_object, exit_pos_x, exit_pos_y, exit_pos_z, exit_world, exit_interior);
  1855. }
  1856. // Pickups
  1857. new Result:pickup_result = sql_query(sqlHandle, "SELECT id, object_id, pos_x, pos_y, pos_z, world_id, interior_id, type_id FROM pickup");
  1858. for(new i = 0; i < sql_num_rows(pickup_result); i++){
  1859. new id = sql_get_field_assoc_int(pickup_result, "id");
  1860. new object_id = sql_get_field_assoc_int_ex(pickup_result, i, "object_id");
  1861. new Float:pos_x = sql_get_field_assoc_float_ex(pickup_result, i, "pos_x");
  1862. new Float:pos_y = sql_get_field_assoc_float_ex(pickup_result, i, "pos_y");
  1863. new Float:pos_z = sql_get_field_assoc_float_ex(pickup_result, i, "pos_z");
  1864. new world_id = sql_get_field_assoc_int_ex(pickup_result, i, "world_id");
  1865. new interior_id = sql_get_field_assoc_int_ex(pickup_result, i, "interior_id");
  1866. new type_id = sql_get_field_assoc_int_ex(pickup_result, i, "type_id");
  1867. new pickupid = createDynamicPickup(object_id, pos_x, pos_y, pos_z, world_id, interior_id, type_id);
  1868. printf("On connect pickupid: %i", pickupid);
  1869. // Update pickup record
  1870. new pickup_query[44 + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  1871. format(pickup_query, sizeof(pickup_query), "UPDATE pickup SET pickup_id = %i WHERE id = %i", pickupid, id);
  1872. sql_query(sqlHandle, pickup_query);
  1873. }
  1874. // Hobo's with a cane (0 ammo value makes them lose the cane as soon as they switch weapon)
  1875. // Only homeless skins, as players should slowly class up in society.
  1876. AddPlayerClass(134, -184.7607, 950.5010, 16.7740, 358.3032, 15, 0, 0, 0, 0, false); // Fort Carson West boulevard right curb.
  1877. AddPlayerClass(10, -184.7607, 950.5010, 16.7740, 358.3032, 15, 0, 0, 0, 0, false); // Fort Carson West boulevard right curb.
  1878. AddPlayerClass(78, 111.0115, 1189.2029, 18.1627, 89.0095, 15, 0, 0, 0, 0, false); // Fort Carson South boulevard left curb.
  1879. AddPlayerClass(129, 111.0115, 1189.2029, 18.1627, 89.0095, 15, 0, 0, 0, 0, false); // Fort Carson South boulevard left curb.
  1880. AddPlayerClass(162, -109.4227, 1242.4860, 16.8223, 183.5798, 15, 0, 0, 0, 0, false); // Fort Carson East boulevard left curb.
  1881. AddPlayerClass(77, -109.4227, 1242.4860, 16.8223, 183.5798, 15, 0, 0, 0, 0, false); // Fort Carson East boulevard left curb.
  1882. AddPlayerClass(79, -201.5379, 948.1683, 15.9131, 359.9720, 15, 0, 0, 0, 0, false); // Fort Carson West boulevard left curb.
  1883. AddPlayerClass(196, -201.5379, 948.1683, 15.9131, 359.9720, 15, 0, 0, 0, 0, false); // Fort Carson West boulevard left curb.
  1884. AddPlayerClass(239, 62.4694, 1205.0531, 18.8153, 89.9380, 15, 0, 0, 0, 0, false); // Fort Carson South boulevard right curb.
  1885. AddPlayerClass(89, 62.4694, 1205.0531, 18.8153, 89.9380, 15, 0, 0, 0, 0, false); // Fort Carson South boulevard right curb.
  1886. AddPlayerClass(135, -126.0831, 1242.5745, 18.6138, 183.2986, 15, 0, 0, 0, 0, false); // Fort Carson East boulevard right curb.
  1887. AddPlayerClass(197, -126.0831, 1242.5745, 18.6138, 183.2986, 15, 0, 0, 0, 0, false); // Fort Carson East boulevard right curb.
  1888. return 1;
  1889. }
  1890. public OnGameModeExit(){
  1891. // Cycle every player
  1892. for(new playerid, a = GetMaxPlayers(); playerid < a; playerid++){
  1893. if(IsPlayerConnected(playerid)){
  1894. // Set name back to username
  1895. //new client_connect_username[MAX_PLAYER_NAME + 1];
  1896. //GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid);
  1897. //SetPlayerName(playerid, client_connect_username); // Change name in-game back to username, for login after restart PROBLEM: Crashses the server on GMX.
  1898. deleteAllGVars(playerid); // Delete GVars as per https://forum.sa-mp.com/showthread.php?t=151076
  1899. // TODO think of somthing for the usernames, kickign every player, or accapting character names as usersnames.
  1900. }
  1901. }
  1902. logger(LOGLEVEL_NOTICE, "* Global game-mode termination."); // Log event
  1903. sql_wait(sqlHandle); // Wait for queries to finish.
  1904. sql_disconnect(sqlHandle); // Disconnect from database.
  1905. DiscordEcho("* Global game-mode termination.", ECHO_CHANNEL); // Notify discord
  1906. //DiscordEcho("* Global game-mode termination.", MAIN_CHANNEL); // Enable when stable
  1907. return 1;
  1908. }
  1909. public OnPlayerRequestClass(playerid, classid){ // Skin selection before spawn.
  1910. if(scriptDebug){
  1911. new message[23 + 4 + MAX_PLAYER_NAME + 1];
  1912. format(message, sizeof(message), "* [%i] %s Class selection.", playerid, getCharacterName(playerid));
  1913. logger(LOGLEVEL_DEBUG, message); // Log event.
  1914. }
  1915. SetPlayerPos(playerid, -185.5514, 944.2042, 15.9337); // In front of Fort Carson city limits sign.
  1916. SetPlayerFacingAngle(playerid, 182.7345); // Charater looks toward the camera.
  1917. SetPlayerCameraPos(playerid, -185.5514, 939.0957, 15.6594); // Further in front of the Fort Carson city limits sign.
  1918. SetPlayerCameraLookAt(playerid, -185.5514, 944.2042, 15.9337); // In front of Fort Carson city limits sign.
  1919. return 1; // Must return one, or skin selection breaks
  1920. }
  1921. public OnPlayerConnect(playerid){
  1922. SetPlayerColor(playerid, COLOR_BLACK);
  1923. // Create & populate variables
  1924. new playername[MAX_PLAYER_NAME + 1], playerip[MAX_SQL_IP + 1];
  1925. playername = getPlayerName(playerid);
  1926. GetPlayerIp(playerid, playerip, sizeof(playerip));
  1927. // Global connection notification
  1928. new admin_message[23 + MAX_PLAYER_NAME + MAX_SQL_IP + 1];
  1929. format(admin_message, sizeof(admin_message), "* [%d] %s (IP: %s) connected.", playerid, getCharacterName(playerid), playerip);
  1930. logger(LOGLEVEL_INFO, admin_message); // Log event
  1931. sendToAdmins(COLOR_NOTICE, admin_message); // Notify all admins.
  1932. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL); // Notify Discord admin echo.
  1933. // Create IP record or update connection attempts
  1934. new ip_query[109 + MAX_SQL_IP + 1];
  1935. format(ip_query, sizeof(ip_query), "INSERT INTO ip(address) VALUES('%s') ON CONFLICT (address) DO UPDATE SET connections = ip.connections+1", playerip);
  1936. sql_query(sqlHandle, ip_query);
  1937. // Check if IP is banned
  1938. new ip_id = getIPID(playerid);
  1939. new ban_query[75 + MAX_SQL_INTEGER + 1];
  1940. format(ban_query, sizeof(ban_query), "SELECT id, reason FROM ip_ban WHERE ip_id = %i AND expires > NOW()::timestamp", ip_id);
  1941. new Result:ban_result = sql_query(sqlHandle, ban_query);
  1942. if(sql_num_rows(ban_result) > 0){ // Banned
  1943. new kick_message[8 + MAX_SQL_REASON + 1];
  1944. format(kick_message, sizeof(kick_message), "Banned: %s", sql_get_field_assoc_int(ban_result, "reason"));
  1945. kickPlayer(playerid, -1, kick_message, 1);
  1946. }
  1947. // Get user record
  1948. new escaped_username[MAX_PLAYER_NAME + 1], user_query[47 + MAX_PLAYER_NAME + 1]; // Should be longer to allow for escaped characters
  1949. sql_escape_string(sqlHandle, playername, escaped_username, sizeof(escaped_username)); // Escape player name
  1950. format(user_query, sizeof(user_query), "SELECT id FROM \"user\" WHERE name = '%s'", escaped_username);
  1951. //new Result:result = sqlQuery(sqlHandle, user_query); // Middleware broken.
  1952. new Result:result = sql_query(sqlHandle, user_query);
  1953. SetGVarString("client_connect_username", playername, playerid); // Used by register, DIALOG_LOGIN, getUserID & OnGameModeExit
  1954. if(sql_num_rows(result) == 0){ // Unkown user
  1955. SetGVarInt("userlevel", UNREGISTERED_PLAYER, playerid); // Set userlevel unregistered
  1956. changeName(playerid, playername); // Check, force and set role-play name
  1957. }
  1958. else{ // Known user
  1959. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Sign in", "Enter your password to log on", "Log in", "Cancel"); // Show password confirmation dialog
  1960. }
  1961. //return 1;
  1962. }
  1963. public OnPlayerDisconnect(playerid, reason){
  1964. if(GetPlayerState(playerid) != PLAYER_STATE_NONE){ // Only save character if spawned
  1965. savePlayerState(playerid); // Save character
  1966. }
  1967. deleteAllGVars(playerid); // Delete GVars as per https://forum.sa-mp.com/showthread.php?t=151076
  1968. new playername[MAX_PLAYER_NAME + 1], message[40 + 4 + MAX_PLAYER_NAME + 1];
  1969. playername = getPlayerName(playerid);
  1970. switch(reason){
  1971. case 0: format(message, sizeof(message), "* [%i] %s disconnected. (Lost Connection)", playerid, getCharacterName(playerid));
  1972. case 1: format(message, sizeof(message), "* [%i] %s disconnected. (Leaving)", playerid, getCharacterName(playerid));
  1973. case 2: format(message, sizeof(message), "* [%i] %s disconnected. (Kicked)", playerid, getCharacterName(playerid)); // Leave this in place for RCON kicks.
  1974. }
  1975. logger(LOGLEVEL_INFO, message); // Log event
  1976. SendClientMessageToAll(COLOR_NOTICE, message); // Notify all players.
  1977. DiscordEcho(message, ECHO_CHANNEL); // Notify discord.
  1978. return 1;
  1979. }
  1980. public OnPlayerSpawn(playerid){
  1981. if(scriptDebug){ // Log event in case of debugging.
  1982. new message[MAX_PLAYER_NAME + 14 + 1];
  1983. format(message, sizeof(message), "* [%i] %s spawned.", playerid, getCharacterName(playerid));
  1984. logger(LOGLEVEL_DEBUG, message); // Log event.
  1985. }
  1986. if(GetGVarInt("userlevel", playerid) == UNREGISTERED_PLAYER){ // Unregistered player.
  1987. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "SERVER: To reserve your name, save your character, statistics and money, type: /register");
  1988. }
  1989. return 1;
  1990. }
  1991. public OnPlayerDeath(playerid, killerid, reason){
  1992. new message[15 + MAX_PLAYER_NAME + 1];
  1993. format(message, sizeof(message), "* [%d] %s died.", playerid, getCharacterName(playerid)); // TODO Add killerid & reason.
  1994. logger(LOGLEVEL_DEBUG, message); // Log event
  1995. DiscordEcho(message, ADMIN_ECHO_CHANNEL); // Notify Discord admin echo.
  1996. //ResetPlayerMoney(playerid); TODO test if required
  1997. //SpawnPlayer(playerid);
  1998. return 1;
  1999. }
  2000. public OnVehicleSpawn(vehicleid) // TODO for 0.0a
  2001. {
  2002. return 1;
  2003. }
  2004. public OnVehicleDeath(vehicleid, killerid) // TODO for 0.0a
  2005. {
  2006. return 1;
  2007. }
  2008. public OnPlayerText(playerid, text[]){
  2009. new shortcut_message[128 + 1];
  2010. strfromliteral(shortcut_message, text);
  2011. strdel(shortcut_message, 0, 1); // Remove chat character from text
  2012. switch(strgetfirstc(text)){
  2013. case '`': {
  2014. if(GetGVarInt("chatmode", playerid) == CHAT_LOCAL){
  2015. sendToChat(playerid, CHAT_GLOBAL, shortcut_message, 0, DCC_INVALID_USER);
  2016. }
  2017. else if (GetGVarInt("chatmode", playerid) == CHAT_GLOBAL){
  2018. sendToChat(playerid, CHAT_LOCAL, shortcut_message, 0, DCC_INVALID_USER);
  2019. }
  2020. else{
  2021. sendToChat(playerid, CHAT_GLOBAL, shortcut_message, 0, DCC_INVALID_USER);
  2022. }
  2023. }
  2024. case '~': {sendToChat(playerid, CHAT_GANG, shortcut_message, 0, DCC_INVALID_USER);}
  2025. case '!': {sendToChat(playerid, CHAT_FACTION, shortcut_message, 0, DCC_INVALID_USER);}
  2026. case '@': {sendToChat(playerid, CHAT_CREW, shortcut_message, 0, DCC_INVALID_USER);}
  2027. case '#': {sendToChat(playerid, CHAT_ADMIN, shortcut_message, 0, DCC_INVALID_USER);}
  2028. case '$': {sendToChat(playerid, CHAT_GANG_OC, shortcut_message, 0, DCC_INVALID_USER);}
  2029. case '%': {sendToChat(playerid, CHAT_FACTION_OC, shortcut_message, 0, DCC_INVALID_USER);}
  2030. case '^': {sendToChat(playerid, CHAT_MANAGEMENT, shortcut_message, 0, DCC_INVALID_USER);}
  2031. //case '$': {sendToChat(playerid, CHAT_MANAGEMENT, shortcut_message[]);}
  2032. case '&': {sendToChat(playerid, CHAT_VIP, shortcut_message, 0, DCC_INVALID_USER);}
  2033. case '*': {sendToChat(playerid, CHAT_UNDERCOVER, shortcut_message, 0, DCC_INVALID_USER);}
  2034. case '+': {sendToChat(playerid, CHAT_CALL, shortcut_message, 0, DCC_INVALID_USER);}
  2035. case '-': {sendToChat(playerid, CHAT_SMS, shortcut_message, 0, DCC_INVALID_USER);}
  2036. case '=': {sendToChat(playerid, CHAT_RADIO, shortcut_message, 0, DCC_INVALID_USER);}
  2037. case '>': {
  2038. new recipient_id, message[128 + 1];
  2039. if (sscanf(shortcut_message, "u s", recipient_id, message)){
  2040. SendClientMessage(playerid, COLOR_COMMAND_OUTPUT, "Usage: > <playerid> <message>");
  2041. }
  2042. else{
  2043. sendPM(playerid, message, recipient_id);
  2044. }
  2045. }
  2046. default:{
  2047. new chatmode = GetGVarInt("chatmode", playerid), message[128 + 1];
  2048. strmid(message, text, 0, 128);
  2049. // message = text;
  2050. if(!chatmode){ // Default is local chat
  2051. sendToChat(playerid, CHAT_LOCAL, message, 0, DCC_INVALID_USER);
  2052. }
  2053. else{ // Send to preferred chat
  2054. printf("chatmode: %i", chatmode);
  2055. sendToChat(playerid, chatmode, message, 0, DCC_INVALID_USER);
  2056. }
  2057. }
  2058. }
  2059. return 0; // Return 1 for default behavior, return 0 to disable default output.
  2060. }
  2061. public OnPlayerCommandText(playerid, cmdtext[]){
  2062. if(scriptDebug){ // Log event in case of debugging.
  2063. new message[5 + 4 + MAX_PLAYER_NAME + 128 + 1]; // 128 = samp text input limit.
  2064. format(message, sizeof(message), "[%d] %s: %s", playerid, getCharacterName(playerid), cmdtext);
  2065. logger(LOGLEVEL_COMMAND, message); // Log event
  2066. }
  2067. return 0;
  2068. }
  2069. public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger) // TODO for 0.0a
  2070. {
  2071. return 1;
  2072. }
  2073. public OnPlayerExitVehicle(playerid, vehicleid) // TODO for 0.0a
  2074. {
  2075. return 1;
  2076. }
  2077. public OnPlayerStateChange(playerid, newstate, oldstate) // TODO for 0.0a
  2078. {
  2079. return 1;
  2080. }
  2081. public OnPlayerEnterCheckpoint(playerid) // TODO for 0.0a
  2082. {
  2083. return 1;
  2084. }
  2085. public OnPlayerLeaveCheckpoint(playerid) // TODO for 0.0a
  2086. {
  2087. return 1;
  2088. }
  2089. public OnPlayerEnterRaceCheckpoint(playerid) // TODO for 0.0a
  2090. {
  2091. return 1;
  2092. }
  2093. public OnPlayerLeaveRaceCheckpoint(playerid) // TODO for 0.0a
  2094. {
  2095. return 1;
  2096. }
  2097. public OnRconCommand(cmd[]){ // The website and some cronjobs do RCON commands. TODO create filter not to show some commands to preven spam
  2098. new message[8 + 128 + 1]; // Max samp message legnth = 128.
  2099. format(message, sizeof(message), "* RCON: %s", cmd);
  2100. logger(LOGLEVEL_NOTICE, message); // Log event
  2101. DiscordEcho(message, MANAGEMENT_CHANNEL);
  2102. return 1;
  2103. }
  2104. public OnPlayerRequestSpawn(playerid){ // After picking a skin in class selection.
  2105. SetPlayerColor(playerid, COLOR_WHITE);
  2106. new playername[MAX_PLAYER_NAME + 1], message[14 + MAX_PLAYER_NAME + 1];
  2107. playername = getPlayerName(playerid);
  2108. if(scriptDebug){ // Only log spawns when debuggins script.
  2109. format(message, sizeof(message), "* [%d] %s Chose a character.", playerid, getCharacterName(playerid));
  2110. logger(LOGLEVEL_DEBUG, message); // Log event
  2111. }
  2112. if(GetGVarInt("userlevel", playerid) > UNREGISTERED_PLAYER){ // Registered player
  2113. createCharacterRecord(playerid, getUserID(playerid)); // Save character
  2114. new client_connect_username[MAX_PLAYER_NAME + 1], admin_message[25 + 4 + MAX_PLAYER_NAME + MAX_PLAYER_NAME + 1];
  2115. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid); // Get client connect name
  2116. format(admin_message, sizeof(admin_message), "[%i] %s has been created by %s.", playerid, getCharacterName(playerid), client_connect_username);
  2117. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  2118. }
  2119. return 1;
  2120. }
  2121. public OnObjectMoved(objectid) // TODO for 0.0a
  2122. {
  2123. return 1;
  2124. }
  2125. public OnPlayerObjectMoved(playerid, objectid) // TODO for 0.0a
  2126. {
  2127. return 1;
  2128. }
  2129. //public OnPlayerPickUpPickup(playerid, pickupid){} // Replaced byOnPlayerPickUpDynamicPickup() streamer.inc
  2130. public OnPlayerPickUpDynamicPickup(playerid, pickupid){ // Requires streamer
  2131. new type = GetGVarInt("pickup_type", pickupid);
  2132. // Special pickup types first, rugular in the else{} conditional statement
  2133. if(type == PICKUP_PORTAL){
  2134. // Do nothing if the player just used a pickup
  2135. if(GetGVarInt("disable_pickups", playerid)){
  2136. return 0;
  2137. }
  2138. new Float:x = GetGVarFloat("pickup_x", pickupid);
  2139. new Float:y = GetGVarFloat("pickup_y", pickupid);
  2140. new Float:z = GetGVarFloat("pickup_z", pickupid);
  2141. new world = GetGVarInt("pickup_world", pickupid);
  2142. new interior = GetGVarInt("pickup_interior", pickupid);
  2143. // Don't releport when the exit is not set
  2144. if(x == 0 && y == 0 && z == 0){
  2145. return 0;
  2146. }
  2147. // Create dynamic area and temporarily disable pickups for player
  2148. new area = CreateDynamicCircle(x, y, 1.7, world, -1, playerid);
  2149. SetGVarInt("disable_pickups", area, playerid);
  2150. // Teleport player
  2151. SetPlayerPos(playerid, x, y, z);
  2152. if(world != -1){SetPlayerVirtualWorld(playerid, world);}
  2153. SetPlayerInterior(playerid, interior);
  2154. }
  2155. else{
  2156. // Do nothing if the player just used a pickup
  2157. if(GetGVarInt("disable_pickups", playerid)){
  2158. return 0;
  2159. }
  2160. // Create dynamic area and temporarily disable pickups for player
  2161. new Float:x, Float:y, Float:z;
  2162. GetPlayerPos(playerid, x, y, z);
  2163. new area = CreateDynamicCircle(x, y, 1, GetPlayerVirtualWorld(playerid), -1, playerid);
  2164. SetGVarInt("disable_pickups", area, playerid);
  2165. // Regular pickup types
  2166. switch(type){
  2167. case PICKUP_FACTION_PD: {
  2168. switch(GetGVarInt("job", playerid)){
  2169. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_PD, DIALOG_STYLE_MSGBOX, "Active police duty", "Go on police duty as a rookie cop?", "Yes", "No");}
  2170. case JOB_POLICE:{ShowPlayerDialog(playerid, DIALOG_DUTY_PD, DIALOG_STYLE_MSGBOX, "Active police duty", "Go off police duty?", "Yes", "No");}
  2171. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  2172. }
  2173. }
  2174. case PICKUP_FACTION_MD:{
  2175. switch(GetGVarInt("job", playerid)){
  2176. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_MD, DIALOG_STYLE_MSGBOX, "Active medic duty", "Go on medic duty as a rookie paramedic?", "Yes", "No");}
  2177. case JOB_MEDIC:{ShowPlayerDialog(playerid, DIALOG_DUTY_MD, DIALOG_STYLE_MSGBOX, "Active medic duty", "Go off paramedic duty?", "Yes", "No");}
  2178. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you have another job.");}
  2179. }
  2180. }
  2181. case PICKUP_FACTION_FD:{
  2182. printf("jobid: %i", GetGVarInt("job", playerid));
  2183. switch(GetGVarInt("job", playerid)){
  2184. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_FD, DIALOG_STYLE_MSGBOX, "Active fire duty", "Go on fire duty as a rookie firefighter?", "Yes", "No");}
  2185. case JOB_FIRE:{ShowPlayerDialog(playerid, DIALOG_DUTY_FD, DIALOG_STYLE_MSGBOX, "Active firefighter duty", "Go off firefighter duty?", "Yes", "No");}
  2186. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you have another job.");}
  2187. }
  2188. }
  2189. case PICKUP_FACTION_FBI:{
  2190. switch(GetGVarInt("job", playerid)){
  2191. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_FBI, DIALOG_STYLE_MSGBOX, "Active FBI duty", "Go on FBI duty as a rookie agent?", "Yes", "No");}
  2192. case JOB_FBI:{ShowPlayerDialog(playerid, DIALOG_DUTY_FBI, DIALOG_STYLE_MSGBOX, "Active medic duty", "Go off FBI duty?", "Yes", "No");}
  2193. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you have another job.");}
  2194. }
  2195. }
  2196. case PICKUP_FACTION_DMV:{
  2197. switch(GetGVarInt("job", playerid)){
  2198. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_DMV, DIALOG_STYLE_MSGBOX, "Active DMV duty", "Go on DMV duty as a rookie service officer?", "Yes", "No");}
  2199. case JOB_DMV:{ShowPlayerDialog(playerid, DIALOG_DUTY_DMV, DIALOG_STYLE_MSGBOX, "Active DMV duty", "Go off DMV duty?", "Yes", "No");}
  2200. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you have another job.");}
  2201. }
  2202. }
  2203. case PICKUP_FACTION_NEWS:{
  2204. switch(GetGVarInt("job", playerid)){
  2205. case JOB_NONE:{ShowPlayerDialog(playerid, DIALOG_DUTY_NEWS, DIALOG_STYLE_MSGBOX, "Active broadcasting duty", "Go on network duty as a rookie reporter?", "Yes", "No");}
  2206. case JOB_NEWS:{ShowPlayerDialog(playerid, DIALOG_DUTY_NEWS, DIALOG_STYLE_MSGBOX, "Active broadcasting duty", "Go off network duty?", "Yes", "No");}
  2207. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you have another job.");}
  2208. }
  2209. }
  2210. }
  2211. }
  2212. return 1;
  2213. }
  2214. public OnPlayerLeaveDynamicArea(playerid, areaid){ // Requires streamer
  2215. // Reactivate pickup after player leaves it
  2216. new area = GetGVarInt("disable_pickups", playerid);
  2217. if(area == 0 && areaid != 0){ // Stop if player had not had this area disabled (With the exception of areaid 0 as GetVarInt() returns 0 on null)
  2218. return;
  2219. }
  2220. else if(area == 0){ // Player has not had picks disabled
  2221. return;
  2222. }
  2223. if(area == areaid){ // Player had this pickup disabled
  2224. DestroyDynamicArea(GetGVarInt("disable_pickups", playerid));
  2225. DeleteGVar("disable_pickups", playerid);
  2226. }
  2227. }
  2228. public OnVehicleMod(playerid, vehicleid, componentid) // TODO for 0.0a
  2229. {
  2230. return 1;
  2231. }
  2232. public OnVehiclePaintjob(playerid, vehicleid, paintjobid) // TODO for 0.0a
  2233. {
  2234. return 1;
  2235. }
  2236. public OnVehicleRespray(playerid, vehicleid, color1, color2) // TODO for 0.0a
  2237. {
  2238. return 1;
  2239. }
  2240. public OnPlayerSelectedMenuRow(playerid, row) // TODO for 0.0a
  2241. {
  2242. return 1;
  2243. }
  2244. public OnPlayerExitedMenu(playerid) // TODO for 0.0a
  2245. {
  2246. return 1;
  2247. }
  2248. public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid) // TODO for 0.0a
  2249. {
  2250. return 1;
  2251. }
  2252. public OnPlayerKeyStateChange(playerid, newkeys, oldkeys) // TODO for 0.0a
  2253. {
  2254. return 1;
  2255. }
  2256. public OnRconLoginAttempt(ip[], password[], success){
  2257. new message[30 + MAX_SQL_IP + 1];
  2258. if(success){
  2259. format(message, sizeof(message), "* [%s] authenticated via RCON.", ip);
  2260. }
  2261. else{
  2262. format(message, sizeof(message), "* [%s] invalid RCON authentication.", ip);
  2263. }
  2264. logger(LOGLEVEL_NOTICE, message); // Log event
  2265. DiscordEcho(message, MANAGEMENT_CHANNEL); // Notify Discord management.
  2266. return 1;
  2267. }
  2268. public OnPlayerUpdate(playerid) // Don't use for now.
  2269. {
  2270. return 1;
  2271. }
  2272. public OnPlayerStreamIn(playerid, forplayerid){
  2273. return 1;
  2274. }
  2275. public OnPlayerStreamOut(playerid, forplayerid) // TODO for 0.0a
  2276. {
  2277. return 1;
  2278. }
  2279. public OnVehicleStreamIn(vehicleid, forplayerid) // TODO for 0.0a
  2280. {
  2281. return 1;
  2282. }
  2283. public OnVehicleStreamOut(vehicleid, forplayerid) // TODO for 0.0a
  2284. {
  2285. return 1;
  2286. }
  2287. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]){
  2288. switch(dialogid){
  2289. case DIALOG_CHANGENAME:{
  2290. if(GetGVarInt("userlevel", playerid) > UNREGISTERED_PLAYER){ // Registered player
  2291. if(!response){ // User aborted
  2292. return 0; // Allow escaping dialogm without forcing to continue
  2293. }
  2294. }
  2295. changeName(playerid, inputtext); // Forced name check and change
  2296. }
  2297. case DIALOG_REGISTER:{
  2298. if(response){ // If they clicked 'Yes' or pressed enter
  2299. // Check password complexity
  2300. new Regex:r = Regex_New("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[0-9!@#\\$%\\^&\\*\\(\\)\\-\\_=+[{\\]}\\\\|;:'\",<.>\\/?]).{8,}$"); // Regex password filter
  2301. new isSecurePassword = Regex_Check(inputtext, r); // Validate name to filter
  2302. Regex_Delete(r);
  2303. if(!isSecurePassword){ // Insecure password
  2304. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Insecure password", "Enter a secure password, containg at least:\n\n * A lowercase letter (a-z)\n * A capiral letter (A-Z)\n * A number (0-9).\n * A character that is not a letter (0-9!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?).\n * 8 characters.", "Register", "Cancel"); // Show password requirements.
  2305. }
  2306. else { // Secure password
  2307. // Hash password
  2308. new buffer[MAX_SQL_HASH + 1], hash[MAX_SQL_HASH + 1];
  2309. WP_Hash(buffer, sizeof(buffer), inputtext);
  2310. GetGVarString("hash", hash, sizeof(hash), playerid);
  2311. if(isempty(hash)){ // First password dialog
  2312. SetGVarString("hash", buffer, playerid); // Save password has a GVar
  2313. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Password confirmation", "Repeat your password to confirm.", "Register", "Cancel"); // Show password confirmation dialog
  2314. }
  2315. else{ // Password confirmation
  2316. if(!isequal(hash, buffer)){ // Password does not match confirmation
  2317. DeleteGVar("hash", playerid);
  2318. SendClientMessage(playerid, COLOR_RED, "ERROR: Password does not match password confirmation.");
  2319. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Password", "Enter the same password twice.", "Continue", "Cancel"); // Password prompt
  2320. }
  2321. else{ // Password matches confirmation
  2322. DeleteGVar("hash", playerid);
  2323. new client_connect_username[MAX_PLAYER_NAME + 1], playerIP[MAX_SQL_IP + 1], escaped_username[MAX_PLAYER_NAME + 1];
  2324. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid);
  2325. GetPlayerIp(playerid, playerIP, sizeof(playerIP));
  2326. sql_escape_string(sqlHandle, client_connect_username, escaped_username, sizeof(escaped_username));
  2327. // Create user record
  2328. new user_query[61 + MAX_PLAYER_NAME + MAX_SQL_HASH + 1 + MAX_SQL_IP + 1];
  2329. format(user_query, sizeof(user_query), "INSERT INTO \"user\"(name, password) VALUES('%s', '%s')", escaped_username, hash);
  2330. /*new Result:user_result = sql_query(sqlHandle, user_query);
  2331. //new id = sql_insert_id(user_result); // Broken, always returns 0.
  2332. // sql_insert_id workaround*/
  2333. sql_query(sqlHandle, user_query);
  2334. new id = getUserID(playerid); // Get ID user user record
  2335. SetGVarInt("userlevel", REGISTERED_PLAYER, playerid);
  2336. // Create user_ip relation table record
  2337. new user_ip_query[50 + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1 ];
  2338. format(user_ip_query, sizeof(user_ip_query), "INSERT INTO user_ip(id, id) VALUES(%i, %i)", getIPID(playerid), id);
  2339. sql_query(sqlHandle, user_ip_query);
  2340. createCharacterRecord(playerid, id); // Save character
  2341. // Inform user
  2342. new dialogMessage[135 + MAX_PLAYER_NAME + 1], message[31 + MAX_PLAYER_NAME + 1];
  2343. format(dialogMessage, sizeof(dialogMessage), "To login as any of your characters, connect as: \nRemember your username carefully, as you have to use it to connect with SA-MP client!", client_connect_username);
  2344. ShowPlayerDialog(playerid, DIALOG_ACCOUNT_CREATED, DIALOG_STYLE_MSGBOX, "Account created", dialogMessage, "Play", "");
  2345. format(message, sizeof(message), "SERVER: Remember your username, %s!", client_connect_username);
  2346. SendClientMessage(playerid, COLOR_WARNING, message);
  2347. // send discord admin echo
  2348. new admin_message[30 + 4 + MAX_PLAYER_NAME + 1];
  2349. format(admin_message, sizeof(admin_message), "[%i] %s has registered an account.", playerid, client_connect_username);
  2350. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  2351. }
  2352. }
  2353. }
  2354. }
  2355. else{ // Pressed ESC or clicked cancel
  2356. DeleteGVar("hash", playerid);
  2357. }
  2358. }
  2359. case DIALOG_LOGIN:{
  2360. if(response){ // If they clicked 'Yes' or pressed enter
  2361. // Escape username
  2362. new client_connect_username[MAX_PLAYER_NAME + 1], escaped_username[MAX_PLAYER_NAME + 1];
  2363. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid);
  2364. sql_escape_string(sqlHandle, client_connect_username, escaped_username, sizeof(escaped_username));
  2365. // Get account
  2366. new user_query[82 + MAX_PLAYER_NAME + 1], hash[MAX_SQL_HASH + 1];
  2367. format(user_query, sizeof(user_query), "SELECT id, password, level FROM \"user\" WHERE name = '%s'", escaped_username);
  2368. new Result:user_result = sql_query(sqlHandle, user_query);
  2369. sql_get_field_assoc_ex(user_result, 0, "password", hash, sizeof(hash));
  2370. // Compare hashes
  2371. new buffer[MAX_SQL_HASH + 1];
  2372. WP_Hash(buffer, sizeof(buffer), inputtext);
  2373. if (!isequal(buffer, hash)){ // Hashes don't match
  2374. // Brute-force protection
  2375. new authentication_count = GetGVarInt("authentication_count", playerid);
  2376. authentication_count++;
  2377. SetGVarInt("authentication_count", authentication_count, playerid);
  2378. ShowPlayerDialog(playerid, DIALOG_LOGIN_FAILED, DIALOG_STYLE_MSGBOX, "Authenticaion failed", "Invalid password.", "Wait", "");
  2379. switch(authentication_count){
  2380. case 0: SetTimerEx("authenticate", 3000, false, "i", playerid); // Return to authentication workflow in 3 second.
  2381. case 1: SetTimerEx("authenticate", 5000, false, "i", playerid); // Return to authentication workflow in 5 seconds.
  2382. case 2: SetTimerEx("authenticate", 7000, false, "i", playerid); // Return to authentication workflow in 7 seconds.
  2383. default: ShowPlayerDialog(playerid, DIALOG_CHANGE_USERNAME, DIALOG_STYLE_INPUT, "Username", "Pick an unregistered username.", "Change", ""); // After 4 failed authentication attempts
  2384. }
  2385. }
  2386. else{ // Hashes match
  2387. // Set userlevel (This has to be done before banning, else the user ban record won't save)
  2388. new userlevel = sql_get_field_assoc_int(user_result, "level");
  2389. printf("Setting userlevel: %i", userlevel);
  2390. SetGVarInt("userlevel", userlevel, playerid);
  2391. // Check bans
  2392. new ban_query[76 + MAX_SQL_INTEGER + 1];
  2393. format(ban_query, sizeof(ban_query), "SELECT user_id FROM user_ban WHERE user_id = %i AND expires > NOW()::timestamp", getUserID(playerid));
  2394. new Result:ban_result = sql_query(sqlHandle, ban_query);
  2395. if(sql_num_rows(ban_result) > 0){ // Banned
  2396. new reason[121 + 1];
  2397. format(reason, sizeof(reason), "Logged in with banned account: %i", sql_get_field_assoc_int(ban_result, "user_id"));
  2398. banPlayer(playerid, -1, reason, 10);
  2399. }
  2400. // Get character names
  2401. characterSelection(playerid);
  2402. }
  2403. }
  2404. else{ // Pressed ESC or clicked cancel
  2405. ShowPlayerDialog(playerid, DIALOG_CHANGE_USERNAME, DIALOG_STYLE_INPUT, "Username", "Pick an unregistered username.", "Change", "");
  2406. }
  2407. }
  2408. case DIALOG_CHANGE_USERNAME:{
  2409. if(response){ // If they clicked 'Yes' or pressed enter
  2410. new Regex:r = Regex_New("^[0-9a-zA-Z\\[\\]\\(\\)\\$@._=]{1,}$"); // Regex name filter
  2411. new isValidName = Regex_Check(inputtext, r);
  2412. Regex_Delete(r);
  2413. if(isValidName){ // Valid name
  2414. // Get user record
  2415. new escaped_username[MAX_PLAYER_NAME + 1], user_query[36 + MAX_PLAYER_NAME + 1];
  2416. sql_escape_string(sqlHandle, inputtext, escaped_username, sizeof(escaped_username)); // Escape player name
  2417. format(user_query, sizeof(user_query), "SELECT id FROM \"user\" WHERE name = '%s'", escaped_username);
  2418. //new Result:result = sqlQuery(sqlHandle, user_query); // Middleware broken.
  2419. new Result:result = sql_query(sqlHandle, user_query);
  2420. if(sql_num_rows(result) > 0){ // Username taken
  2421. ShowPlayerDialog(playerid, DIALOG_CHANGE_USERNAME, DIALOG_STYLE_INPUT, "Username", "Pick an unregistered username.", "Change", "");
  2422. }
  2423. else{ // Username free
  2424. SetGVarString("client_connect_username", inputtext, playerid); // Used by register and DIALOG_LOGIN
  2425. SetPlayerName(playerid, inputtext); // Change name in-game
  2426. return 1; // Do nothing to let player continue class selection
  2427. }
  2428. }
  2429. else{ // Invalid name
  2430. ShowPlayerDialog(playerid, DIALOG_CHANGE_USERNAME, DIALOG_STYLE_INPUT, "Username", "Invalid name. Names may only contain numbers (0-9), letters (a-z) & (A-Z) and special characters ([]()$@._=)", "Change", "");
  2431. }
  2432. }
  2433. else{ // Pick another username
  2434. ShowPlayerDialog(playerid, DIALOG_CHANGE_USERNAME, DIALOG_STYLE_INPUT, "Username", "Pick an unregistered username.", "Change", "");
  2435. }
  2436. }
  2437. case DIALOG_CHARACTERS:{ // TODO set color & skin in case of job
  2438. if(response){ // Spawn as character
  2439. new character_array_string[MAX_CHARACTERS_PER_USER * MAX_SQL_INTEGER + 1], character_array[MAX_CHARACTERS_PER_USER + 1];
  2440. GetGVarString("character_array_string", character_array_string, sizeof(character_array_string), playerid);
  2441. DeleteGVar("character_array_string");
  2442. strtobin(character_array, character_array_string);
  2443. new character_query[124 + MAX_PLAYER_NAME + 1], name[24 + 1];
  2444. format(character_query, sizeof(character_query), "SELECT name, skin_id, cash, armour, health, pos_x, pos_y, pos_z, rotation, world_id, interior_id FROM character WHERE id = %i", character_array[listitem]);
  2445. new Result:character_result = sql_query(sqlHandle, character_query);
  2446. sql_get_field_assoc(character_result, "name", name, sizeof(name));
  2447. new skin_id = sql_get_field_assoc_int(character_result, "skin_id");
  2448. new cash = sql_get_field_assoc_int(character_result, "cash");
  2449. new Float:armour = sql_get_field_assoc_int(character_result, "armour");
  2450. new Float:health = sql_get_field_assoc_int(character_result, "health");
  2451. new Float:pos_x = sql_get_field_assoc_int(character_result, "pos_x");
  2452. new Float:pos_y = sql_get_field_assoc_int(character_result, "pos_y");
  2453. new Float:pos_z = sql_get_field_assoc_int(character_result, "pos_z");
  2454. new Float:rotation = sql_get_field_assoc_int(character_result, "rotation");
  2455. new world_id = sql_get_field_assoc_int(character_result, "world_id");
  2456. new interior_id = sql_get_field_assoc_int(character_result, "interior_id");
  2457. // Temporary bug workaround TODO find cause
  2458. if(pos_x == 0 && pos_y == 0 && pos_z == 0){ // Sometimes this happens. Due to unreliable OnPlayerDisconnect() & OnGamemodeExit(), due to character creation, or due to (forgot the other possiblity, but had a strong hunch)?
  2459. pos_x = -144.0328;
  2460. pos_y = 1225.0564;
  2461. pos_z = 19.8992;
  2462. rotation = 175.5507;
  2463. }
  2464. SetSpawnInfo(playerid, 0, skin_id, pos_x, pos_y, pos_z, rotation, 0, 0, 0, 0, 0, 0);
  2465. SetGVarInt("character_id", character_array[listitem], playerid);
  2466. SetPlayerName(playerid, name); // Change name in-game
  2467. SetPlayerColor(playerid, COLOR_WHITE);
  2468. SpawnPlayer(playerid);
  2469. ResetPlayerMoney(playerid);
  2470. GivePlayerMoney(playerid, cash);
  2471. SetPlayerHealth(playerid, health);
  2472. SetPlayerArmour(playerid, armour);
  2473. SetPlayerVirtualWorld(playerid, world_id);
  2474. SetPlayerInterior(playerid, interior_id);
  2475. // Notify all players
  2476. new message[16 + 4 + MAX_PLAYER_NAME + 1];
  2477. format(message, sizeof(message), "* [%i] %s joined.", playerid, getCharacterName(playerid));
  2478. SendClientMessageToAll(COLOR_NOTICE, message); // Notify all players.
  2479. DiscordEcho(message, ECHO_CHANNEL); // Notify discord public echo
  2480. }
  2481. else{ // New character
  2482. // character cap
  2483. new id = getUserID(playerid);
  2484. new character_query[60 + MAX_SQL_INTEGER + 1];
  2485. format(character_query, sizeof(character_query), "SELECT id FROM character WHERE character_id = %i", id);
  2486. new Result:character_result = sql_query(sqlHandle, character_query);
  2487. printf("%i", sql_num_rows(character_result));
  2488. if(sql_num_rows(character_result) >= MAX_CHARACTERS_PER_USER){ // At or over character limit
  2489. SendClientMessage(playerid, COLOR_WARNING, "SERVER: Maximum characters reached, can not create another.");
  2490. characterSelection(playerid);
  2491. }
  2492. else{
  2493. ShowPlayerDialog(playerid, DIALOG_CHANGENAME, DIALOG_STYLE_INPUT, "Character name", "Pick a name.\n\nExamples:\n Jo_Bo\n Dingle_P._J._Berry\n Jackson_DeForest_Kelley\n MaryJo_Ann_LaFluer", "Change", ""); // Force RP name.
  2494. // changeName(playerid, ""); // Pick name and save character ANNOYING this forces new character creation, no way out.
  2495. }
  2496. }
  2497. }
  2498. case DIALOG_LOGIN_FAILED:{
  2499. ShowPlayerDialog(playerid, DIALOG_LOGIN_FAILED, DIALOG_STYLE_MSGBOX, "Authenticaion failed", "Take some time to think about your password...", "Wait", "Longer");
  2500. }
  2501. case DIALOG_DELETE_CHARACTER:{
  2502. if(response){ // Delete character
  2503. new playername[MAX_PLAYER_NAME + 1];
  2504. playername = getPlayerName(playerid);
  2505. // Checkcharacter amount
  2506. new id = getUserID(playerid), character_query[75 + MAX_SQL_INTEGER + MAX_CHARACTERS_PER_USER_DIGITS + 1];
  2507. format(character_query, sizeof(character_query), "SELECT id, name FROM character WHERE user_id = %i LIMIT %i", id, MAX_CHARACTERS_PER_USER);
  2508. new Result:character_result = sql_query(sqlHandle, character_query);
  2509. if(sql_num_rows(character_result) < 2){ // 1 character or less
  2510. SendClientMessage(playerid, COLOR_WARNING, "SERVER: You can not have less then one character.\nCreate another character,before deleting this one.");
  2511. }
  2512. else{ // More then 1 character
  2513. // delete character record
  2514. new delete_query[50 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  2515. format(delete_query, sizeof(delete_query), "DELETE FROM character WHERE name = '%s' AND user_id = %i", playername, getUserID(playerid));
  2516. sql_query(sqlHandle, delete_query);
  2517. // infordm admin echo
  2518. new client_connect_username[MAX_PLAYER_NAME + 1], message[28 + 4 + MAX_PLAYER_NAME + MAX_PLAYER_NAME + 1];
  2519. GetGVarString("client_connect_username", client_connect_username, sizeof(client_connect_username), playerid); // Get client connect name
  2520. format(message, sizeof(message), "* [%i] %s has been deleted by it's user: %s", playerid, getCharacterName(playerid), client_connect_username);
  2521. DiscordEcho(message, ADMIN_ECHO_CHANNEL);
  2522. sendToAdmins(COLOR_COMMAND_OUTPUT, message);
  2523. // Player must not be spawned or will be able to esacpe the character menu and continue with character without dartabase record
  2524. ForceClassSelection(playerid);
  2525. TogglePlayerSpectating(playerid, true);
  2526. TogglePlayerSpectating(playerid, false);
  2527. characterSelection(playerid);
  2528. }
  2529. }
  2530. }
  2531. case DIALOG_GOTO:{
  2532. if(response){
  2533. switch(listitem){
  2534. case GOTO_CATEGORY_INTERIOR:{
  2535. dialogGotoInterior(playerid);
  2536. }
  2537. /*case GOTO_CATEGORY_PLAYER:{
  2538. dialogGotoPlayer(playerid);
  2539. }*/
  2540. }
  2541. }
  2542. }
  2543. case DIALOG_GOTO_INTERIOR:{
  2544. if(response){
  2545. switch(listitem){
  2546. case INTERIOR_CATEGORY_247:{
  2547. ShowPlayerDialog(playerid, DIALOG_GOTO_247, DIALOG_STYLE_TABLIST, "24/7's", "L-shaped\tBig\tNO EXIT\nOblong\tBig\tNO EXIT\nSquare\tMedium\tCreek, LV\nSquare\tMedium\tNO EXIT\nLong\tSmall\tMulholland\nSquare\tSmall\tWhetstone", "Goto", "Cancel");
  2548. }
  2549. case INTERIOR_CATEGORY_AVIATION:{
  2550. ShowPlayerDialog(playerid, DIALOG_GOTO_AVIATION, DIALOG_STYLE_TABLIST, "Aviation interiors", "Francis Intn'l Airport - Ticket sales\tStarting Cutscene\nFrancis Intn'l Airport - Baggage claim\tStarting Cutscene\nShamal cabin\tMission \"Free Fall\"\nAndromada cargo hold\tMission \"Stowaway\"\nLS Airport, Baggage Reclaim\tCutscene in \"Opening Mission\"", "Goto", "Cancel");
  2551. }
  2552. case INTERIOR_CATEGORY_AMMUNATION:{
  2553. ShowPlayerDialog(playerid, DIALOG_GOTO_AMMUNATION, DIALOG_STYLE_TABLIST, "Ammunation's", "Ocean Flats\tSF\nPalomino Creek\tLV\nAngel Pine\tSF\nEl Quebrados\tLV\n2 Stories/t with Booth and Range\n Booth\n Range", "Goto", "Cancel");
  2554. }
  2555. case INTERIOR_CATEGORY_BUGRLARY:{
  2556. ShowPlayerDialog(playerid, DIALOG_GOTO_BURGLARY, DIALOG_STYLE_TABLIST, "Burglary houses", "Large\t2 story\t3 bedroom clone of house 9\t\nMedium\t1 story\t1 bedroom\tEast LS\nSmall\t1 story\t1 bedroom\tCalton Heights, SF\nVery large\t2 story\t4 bedrooms\nSmall\t1 story\t2 bedrooms\tJefferson LS\nSmall\t1 story\t2 bedrooms\tEast LS\nSmall\t1 story\t 1 bedroom (NO BATHROOM!)", "Goto", "Cancel");
  2557. }
  2558. case INTERIOR_CATEGORY_MISSION:{
  2559. ShowPlayerDialog(playerid, DIALOG_GOTO_MISSION, DIALOG_STYLE_TABLIST, "Mission interiors", "Atrium\tMission \"Just Business\"\tLS\nBig Smoke's Crack Palace\tMission \"End of the Line\"\nJefferson Motel\tMission \"Reuniting the Families\"\tLS\nPleasure Domes/Jizzy's\tMission \"Ice Cold Killa\"\tSF\nRC Battlefield\tMission \"New Model Army\"\nWoozies Apartment/Wu-Zi Mu's\t\tSF\n", "Goto", "Cancel");
  2560. }
  2561. case INTERIOR_CATEGORY_MISSIONEXT:{
  2562. ShowPlayerDialog(playerid, DIALOG_GOTO_MISSIONEXT, DIALOG_STYLE_TABLIST, "Mission exteriors", "Dillimore Gas Station\tMission \"Tanker Commander\"\nLiberty City\tMission \"Saint Marks Bistro\"\nSan Fierro Garage\tDoherty (Locked Camera Position}", "Goto", "Cancel");
  2563. }
  2564. case INTERIOR_CATEGORY_MISSIONHOUSE:{
  2565. ShowPlayerDialog(playerid, DIALOG_GOTO_MISSIONHOUSE, DIALOG_STYLE_TABLIST, "Mission houses", "Burning Desire house\t\tEast LS\nColonel Furhberger's\tMission \"Home Invasion\"\t Los Flores, LS\nRyder's house\nSweet's house\tCutscene in \"First Date\"\nCrack Den\tMission \"Cleaning The Hood\"", "Goto", "Cancel");
  2566. }
  2567. case INTERIOR_CATEGORY_MODSHOP:{
  2568. ShowPlayerDialog(playerid, DIALOG_GOTO_MODDING, DIALOG_STYLE_TABLIST, "Modding shops", "Loco Low Co\tLos Santos\nWheel Arch Angels\tSan Fierro\nTransfender", "Goto", "Cancel");
  2569. }
  2570. case INTERIOR_CATEGORY_POLICE:{
  2571. ShowPlayerDialog(playerid, DIALOG_GOTO_POLICE, DIALOG_STYLE_LIST, "Police departments", "Las Venturas\nLos Santos\nSan Fierro\nBarbara's love nest", "Goto", "Cancel");
  2572. }
  2573. case INTERIOR_CATEGORY_HOUSES:{
  2574. ShowPlayerDialog(playerid, DIALOG_GOTO_HOUSE, DIALOG_STYLE_TABLIST, "Safe houses", "Golden Bed motel room\t\t\nHashbury house\tHashburry\tSF\nThe Johnson house\tGanton\tLS\nMadd Doggs mansion\tMulholland\tLS\nRed Bed motel Room\nVerdant Bluffs safehouse\tVerdant Bluffs\t LV\nUnused safehouse\tLarge modern safehouse", "Goto", "Cancel");
  2575. }
  2576. case INTERIOR_CATEGORY_SHOPS:{
  2577. ShowPlayerDialog(playerid, DIALOG_GOTO_SHOP, DIALOG_STYLE_TABLIST, "Shops & casino's", "Tattoos\tIdlewood\tLS\nBurger Shot\tWhitewood Estates\nWell Stacked Pizza\tBlueberry\nCluckin' Bell\nCaligulas casino\tThe Strip\tLV\nCasino (Redsands West)\tThe Strip\tLV\n4 Dragons casino\tThe Strip\tLV\nRusty Brown's donuts\tMission \"Burning Desire\"\nZero's RC shop\tGarcia\tSF\nThe Welcome Pump", "Goto", "Cancel");
  2578. }
  2579. case INTERIOR_CATEGORY_STADIA:{
  2580. ShowPlayerDialog(playerid, DIALOG_GOTO_STADIA, DIALOG_STYLE_TABLIST, "Stadia", "Bloodbowl stadium\nKickstart stadium\n8 Track stadium\nDirtbike stadium\n", "Goto", "Cancel");
  2581. }
  2582. }
  2583. }
  2584. else{
  2585. ShowPlayerDialog(playerid, DIALOG_GOTO, DIALOG_STYLE_LIST, "Categories", "Interiors", "Select", "Cancel");
  2586. }
  2587. }
  2588. case DIALOG_GOTO_247:{
  2589. if(response){
  2590. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[25 + 1];
  2591. switch(listitem){
  2592. case INTERIOR_247_LSHAPED:{
  2593. x = -25.7220;
  2594. y = -187.8216;
  2595. z = 1003.5469;
  2596. world = GetPlayerVirtualWorld(playerid);
  2597. interior = 17;
  2598. angle = 5.0760;
  2599. name = "L-shaped ammunation";
  2600. }
  2601. case INTERIOR_247_OBLONG:{
  2602. x = 6.0856;
  2603. y = -28.8966;
  2604. z = 1003.5494;
  2605. world = GetPlayerVirtualWorld(playerid);
  2606. interior = 10;
  2607. angle = 5.0365;
  2608. name = "Oblong ammunation";
  2609. }
  2610. case INTERIOR_247_MEDIUM:{
  2611. x = -30.9875;
  2612. y = -89.6806;
  2613. z = 1003.5469;
  2614. world = GetPlayerVirtualWorld(playerid);
  2615. interior = 18;
  2616. angle = 359.8401;
  2617. name = "Medium ammunation";
  2618. }
  2619. case INTERIOR_247_MEDIUM_NOEXIT:{
  2620. x = -26.1856;
  2621. y = -140.9164;
  2622. z = 1003.5469;
  2623. world = GetPlayerVirtualWorld(playerid);
  2624. interior = 16;
  2625. angle = 2.9087;
  2626. name = "Medium no exit ammunation";
  2627. }
  2628. case INTERIOR_247_LONG:{
  2629. x = -27.844;
  2630. y = 26.6737;
  2631. z = 1003.5573;
  2632. world = GetPlayerVirtualWorld(playerid);
  2633. interior = 4;
  2634. angle = 184.3118;
  2635. name = "Small long ammunation";
  2636. }
  2637. case INTERIOR_247_SQAURE:{
  2638. x = -26.8339,
  2639. y = -55.5846,
  2640. z = 1003.5469,
  2641. world = GetPlayerVirtualWorld(playerid),
  2642. interior = 6,
  2643. angle = 3.9528;
  2644. name = "Small square ammunation";
  2645. }
  2646. }
  2647. new target_player = GetGVarInt("goto_target", playerid);
  2648. DeleteGVar("goto_target", playerid);
  2649. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2650. }
  2651. else{dialogGotoInterior(playerid);}
  2652. }
  2653. case DIALOG_GOTO_AVIATION:{
  2654. if(response){
  2655. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[39 + 1];
  2656. switch(listitem){
  2657. case INTERIOR_AVIATION_TICKET:{
  2658. x = -1827.147338;
  2659. y = 7.207418;
  2660. z = 1061.143554;
  2661. world = GetPlayerVirtualWorld(playerid);
  2662. interior = 14;
  2663. angle = 335.3199;
  2664. name = "Francis Intn'l Airport - Ticket sales";
  2665. }
  2666. case INTERIOR_AVIATION_BAGGAGE:{
  2667. x = -1855.568725;
  2668. y = 41.263156;
  2669. z = 1061.143554;
  2670. world = GetPlayerVirtualWorld(playerid);
  2671. interior = 14;
  2672. angle = 335.3199;
  2673. name = "Francis Intn'l Airport - Baggage claim";
  2674. }
  2675. case INTERIOR_AVIATION_SHAMAL:{
  2676. x = 2.384830;
  2677. y = 33.103397;
  2678. z = 1199.849976 ;
  2679. world = GetPlayerVirtualWorld(playerid);
  2680. interior = 1;
  2681. angle = 359.8401;
  2682. name = "Shamal cabin";
  2683. }
  2684. case INTERIOR_AVIATION_ANDROMADA:{
  2685. x = 315.856170;
  2686. y = 1024.496459;
  2687. z = 1949.797363;
  2688. world = GetPlayerVirtualWorld(playerid);
  2689. interior = 9;
  2690. angle = 359.6368;
  2691. name = "Andromada cargo hold";
  2692. }
  2693. case INTERIOR_AVIATION_LSAIRPORT:{
  2694. x = -1870.80;
  2695. y = 59.81;
  2696. z = 1056.25;
  2697. world = GetPlayerVirtualWorld(playerid);
  2698. interior = 14;
  2699. angle = 85.8541;
  2700. name = "LS Airport, Baggage Reclaim";
  2701. }
  2702. }
  2703. new target_player = GetGVarInt("goto_target", playerid);
  2704. DeleteGVar("goto_target", playerid);
  2705. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2706. }
  2707. else{dialogGotoInterior(playerid);}
  2708. }
  2709. case DIALOG_GOTO_AMMUNATION:{ // TODO there are more ammunations that deserve a booth and range teleport
  2710. if(response){
  2711. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[31 + 1];
  2712. switch(listitem){
  2713. case INTERIOR_AMMU_OCEAN:{
  2714. x = 286.148987;
  2715. y = -40.644398 ;
  2716. z = 1001.569946;
  2717. world = GetPlayerVirtualWorld(playerid);
  2718. interior = 1;
  2719. angle = 0.7529;
  2720. name = "Ocean Flats, SF";
  2721. }
  2722. case INTERIOR_AMMU_PALOMINO:{
  2723. x = 286.800995;
  2724. y = -82.547600;
  2725. z = 1001.539978;
  2726. world = GetPlayerVirtualWorld(playerid);
  2727. interior = 4;
  2728. angle = 290.2195;
  2729. name = "Palomino Creek, LV";
  2730. }
  2731. case INTERIOR_AMMU_ANGEL:{
  2732. x = 296.919983;
  2733. y = -108.071999;
  2734. z = 1001.569946;
  2735. world = GetPlayerVirtualWorld(playerid);
  2736. interior = 6;
  2737. angle = 290.2195;
  2738. name = "Angel Pine, SF";
  2739. }
  2740. case INTERIOR_AMMU_QUEBRADOS:{
  2741. x = 316.524994;
  2742. y = -167.706985;
  2743. z = 999.661987;
  2744. world = GetPlayerVirtualWorld(playerid);
  2745. interior = 6;
  2746. angle = 10.3031;
  2747. name = "El Quebrados, LV";
  2748. }
  2749. case INTERIOR_AMMU_2STORIES:{
  2750. x = 314.820984;
  2751. y = -141.431992;
  2752. z = 999.661987;
  2753. world = GetPlayerVirtualWorld(playerid);
  2754. interior = 7;
  2755. angle = 20.2254;
  2756. name = "2 Stories, with booth and range";
  2757. }
  2758. case INTERIOR_AMMU_BOOTH:{
  2759. x = 302.292877;
  2760. y = -143.139099;
  2761. z = 1004.062500;
  2762. world = GetPlayerVirtualWorld(playerid);
  2763. interior = 7;
  2764. angle = 20.2254;
  2765. name = "Booth";
  2766. }
  2767. case INTERIOR_AMMU_RANGE:{
  2768. x = 280.795104;
  2769. y = -135.203353;
  2770. z = 1004.062500;
  2771. world = GetPlayerVirtualWorld(playerid);
  2772. interior = 7;
  2773. angle = 20.2254;
  2774. name = "Range";
  2775. }
  2776. }
  2777. new target_player = GetGVarInt("goto_target", playerid);
  2778. DeleteGVar("goto_target", playerid);
  2779. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2780. }
  2781. else{dialogGotoInterior(playerid);}
  2782. }
  2783. case DIALOG_GOTO_BURGLARY:{
  2784. if(response){
  2785. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[45 + 1];
  2786. switch(listitem){
  2787. case INTERIOR_BURGRLARY_LARGE:{
  2788. x = 235.508994;
  2789. y = 1189.169897;
  2790. z = 1080.339966;
  2791. world = GetPlayerVirtualWorld(playerid);
  2792. interior = 3;
  2793. angle = 349.4844;
  2794. name = "Large: 2 story, 3 bedroom clone of house 9";
  2795. }
  2796. case INTERIOR_BURGRLARY_MEDIUM:{
  2797. x = 225.756989;
  2798. y = 1240.000000;
  2799. z = 1082.149902;
  2800. world = GetPlayerVirtualWorld(playerid);
  2801. interior = 2;
  2802. angle = 96.2852;
  2803. name = "Medium: 1 story, 1 bedroom";
  2804. }
  2805. case INTERIOR_BURGRLARY_SMALL:{
  2806. x = 223.043991;
  2807. y = 1289.259888;
  2808. z = 1082.199951;
  2809. world = GetPlayerVirtualWorld(playerid);
  2810. interior = 1;
  2811. angle = 359.868;
  2812. name = "Small: 1 story, 1 bedroom";
  2813. }
  2814. case INTERIOR_BURGRLARY_VERYLARGE:{
  2815. x = 225.630997;
  2816. y = 1022.479980;
  2817. z = 1084.069946;
  2818. world = GetPlayerVirtualWorld(playerid);
  2819. interior = 7;
  2820. angle = 270.2654;
  2821. name = "VERY Large: 2 story, 4 bedrooms";
  2822. }
  2823. case INTERIOR_BURGRLARY_5:{
  2824. x = 295.138977;
  2825. y = 1474.469971;
  2826. z = 1080.519897;
  2827. world = GetPlayerVirtualWorld(playerid);
  2828. interior = 15;
  2829. angle = 0;
  2830. name = "Small: 1 story, 2 bedrooms";
  2831. }
  2832. case INTERIOR_BURGRLARY_6:{
  2833. x = 328.493988;
  2834. y = 1480.589966;
  2835. z = 1084.449951;
  2836. world = GetPlayerVirtualWorld(playerid);
  2837. interior = 15;
  2838. angle = 0;
  2839. name = "Small: 1 story, 2 bedrooms";
  2840. }
  2841. case INTERIOR_BURGRLARY_NOBATH:{
  2842. x = 385.803986;
  2843. y = 1471.769897;
  2844. z = 1080.209961;
  2845. world = GetPlayerVirtualWorld(playerid);
  2846. interior = 15;
  2847. angle = 0;
  2848. name = "Small: 1 story, 1 bedroom (NO BATHROOM!)";
  2849. }
  2850. }
  2851. new target_player = GetGVarInt("goto_target", playerid);
  2852. DeleteGVar("goto_target", playerid);
  2853. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2854. }
  2855. else{dialogGotoInterior(playerid);}
  2856. }
  2857. case DIALOG_GOTO_MISSION:{
  2858. if(response){
  2859. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[30 + 1];
  2860. switch(listitem){
  2861. case INTERIOR_MISSION_ATRIUM:{
  2862. x = 1726.18;
  2863. y = -1641.00;
  2864. z = 20.23;
  2865. world = GetPlayerVirtualWorld(playerid);
  2866. interior = 18;
  2867. angle = 172.4193;
  2868. name = "Atrium";
  2869. }
  2870. case INTERIOR_MISSION_BIGSMOKE:{
  2871. x = 2567.52;
  2872. y = -1294.59;
  2873. z = 1063.25 ;
  2874. world = GetPlayerVirtualWorld(playerid);
  2875. interior = 2;
  2876. angle = 254.9548;
  2877. name = "Big Smoke's Crack Palace";
  2878. }
  2879. case INTERIOR_MISSION_JEFFERSON:{
  2880. x = 2220.26;
  2881. y = -1148.01;
  2882. z = 1025.80;
  2883. world = GetPlayerVirtualWorld(playerid);
  2884. interior = 15;
  2885. angle = 273.7328;
  2886. name = "Jefferson Motel";
  2887. }
  2888. case INTERIOR_MISSION_JIZZY:{
  2889. x = -2637.69;
  2890. y = 1404.24;
  2891. z = 906.46;
  2892. world = GetPlayerVirtualWorld(playerid);
  2893. interior = 3;
  2894. angle = 94.6794;
  2895. name = "Pleasure Domes/Jizzy's";
  2896. }
  2897. case INTERIOR_MISSION_RC:{
  2898. x = -1079.99;
  2899. y = 1061.58;
  2900. z = 1343.04;
  2901. world = GetPlayerVirtualWorld(playerid);
  2902. interior = 10;
  2903. angle = 274.5268;
  2904. name = "RC Battlefield";
  2905. }
  2906. case INTERIOR_MISSION_WUZI:{
  2907. x = -2158.72;
  2908. y = 641.29;
  2909. z = 1052.38;
  2910. world = GetPlayerVirtualWorld(playerid);
  2911. interior = 1;
  2912. angle = 86.5402;
  2913. name = "Woozies Apartment/Wu-Zi Mu's";
  2914. }
  2915. }
  2916. new target_player = GetGVarInt("goto_target", playerid);
  2917. DeleteGVar("goto_target", playerid);
  2918. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2919. }
  2920. else{dialogGotoInterior(playerid);}
  2921. }
  2922. case DIALOG_GOTO_MISSIONEXT:{
  2923. if(response){
  2924. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[30 + 1];
  2925. switch(listitem){
  2926. case INTERIOR_MISSIONEXT_GAS:{
  2927. x = 664.19;
  2928. y = -570.73;
  2929. z = 16.34;
  2930. world = GetPlayerVirtualWorld(playerid);
  2931. interior = 0;
  2932. angle = 264.9829;
  2933. name = "Dillimore Gas Station";
  2934. }
  2935. case INTERIOR_MISSIONEXT_LIBERTY:{ // TODO Create extra interior inside the shop
  2936. x = -750.80;
  2937. y = 491.00;
  2938. z = 1371.70;
  2939. world = GetPlayerVirtualWorld(playerid);
  2940. interior = 1;
  2941. angle = 71.7782;
  2942. name = "Liberty City";
  2943. }
  2944. case INTERIOR_MISSIONEXT_SFGARAGE:{ // TODO Create extra interior of area that does not capture the camera & see about the camera camera capturing (Use it for broadcast? & In other world or interior place more usable?)
  2945. x = -2042.42;
  2946. y = 178.59;
  2947. z = 28.84;
  2948. world = GetPlayerVirtualWorld(playerid);
  2949. interior = 1;
  2950. angle = 156.2153;
  2951. name = "San Fierro Garage Interior";
  2952. }
  2953. }
  2954. new target_player = GetGVarInt("goto_target", playerid);
  2955. DeleteGVar("goto_target", playerid);
  2956. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  2957. }
  2958. else{dialogGotoInterior(playerid);}
  2959. }
  2960. case DIALOG_GOTO_MISSIONHOUSE:{
  2961. if(response){
  2962. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[30 + 1];
  2963. switch(listitem){
  2964. case INTERIOR_MISSIONHOUSE_DESIRE:{
  2965. x = 2338.32;
  2966. y = -1180.61;
  2967. z = 1027.98;
  2968. world = GetPlayerVirtualWorld(playerid);
  2969. interior = 5;
  2970. angle = 99.1864;
  2971. name = "Burning Desire House";
  2972. }
  2973. case INTERIOR_MISSIONHOUSE_COLONEL:{
  2974. x = 2807.63;
  2975. y = -1170.15;
  2976. z = 1025.57;
  2977. world = GetPlayerVirtualWorld(playerid);
  2978. interior = 8;
  2979. angle = 193.7117;
  2980. name = "Colonel Furhberger's";
  2981. }
  2982. case INTERIOR_MISSIONHOUSE_RYDER:{
  2983. x = 2451.77;
  2984. y = -1699.80;
  2985. z = 1013.51;
  2986. world = GetPlayerVirtualWorld(playerid);
  2987. interior = 2;
  2988. angle = 314.5253;
  2989. name = "Ryder's House";
  2990. }
  2991. case INTERIOR_MISSIONHOUSE_SWEET:{
  2992. x = 2535.83;
  2993. y = -1674.32;
  2994. z = 1015.50;
  2995. world = GetPlayerVirtualWorld(playerid);
  2996. interior = 1;
  2997. angle = 260.9709;
  2998. name = "Sweet's House";
  2999. }
  3000. case INTERIOR_MISSIONHOUSE_CRACK:{
  3001. x = 318.565;
  3002. y = 1115.210;
  3003. z = 1082.98;
  3004. world = GetPlayerVirtualWorld(playerid);
  3005. interior = 5;
  3006. angle = 267.459;
  3007. name = "Crack den";
  3008. }
  3009. }
  3010. new target_player = GetGVarInt("goto_target", playerid);
  3011. DeleteGVar("goto_target", playerid);
  3012. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3013. }
  3014. else{dialogGotoInterior(playerid);}
  3015. }
  3016. case DIALOG_GOTO_MODDING:{
  3017. if(response){
  3018. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[25 + 1];
  3019. switch(listitem){
  3020. case INTERIOR_MOD_LOCO:{
  3021. x = 616.7820;
  3022. y = -74.8151;
  3023. z = 997.6350;
  3024. world = GetPlayerVirtualWorld(playerid);
  3025. interior = 2;
  3026. angle = 320.9263;
  3027. name = "Loco Low Co";
  3028. }
  3029. case INTERIOR_MOD_WHEEL:{
  3030. x = 615.2851;
  3031. y = -124.2390;
  3032. z = 997.6350;
  3033. world = GetPlayerVirtualWorld(playerid);
  3034. interior = 3;
  3035. angle = 266.5704;
  3036. name = "Wheel Arch Angels";
  3037. }
  3038. case INTERIOR_MOD_TRANSFENDER:{
  3039. x = 617.5380;
  3040. y = -1.9900;
  3041. z = 1000.6829;
  3042. world = GetPlayerVirtualWorld(playerid);
  3043. interior = 1;
  3044. angle = 15.6789;
  3045. name = "Transfender";
  3046. }
  3047. }
  3048. new target_player = GetGVarInt("goto_target", playerid);
  3049. DeleteGVar("goto_target", playerid);
  3050. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3051. }
  3052. else{dialogGotoInterior(playerid);}
  3053. }
  3054. case DIALOG_GOTO_POLICE:{
  3055. if(response){
  3056. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[30 + 1];
  3057. switch(listitem){
  3058. case INTERIOR_PD_LV:{
  3059. x = 288.4723;
  3060. y = 170.0647;
  3061. z = 1007.1794;
  3062. world = GetPlayerVirtualWorld(playerid);
  3063. interior = 3;
  3064. angle = 22.0477;
  3065. name = "Las Venturas police deparment";
  3066. }
  3067. case INTERIOR_PD_LS:{
  3068. x = 246.6695;
  3069. y = 65.8039;
  3070. z = 1003.6406;
  3071. world = GetPlayerVirtualWorld(playerid);
  3072. interior = 6;
  3073. angle = 7.9562;
  3074. name = "Los Santos police deparment";
  3075. }
  3076. case INTERIOR_PD_SF:{
  3077. x = 246.0688;
  3078. y = 108.9703;
  3079. z = 1003.2188;
  3080. world = GetPlayerVirtualWorld(playerid);
  3081. interior = 10;
  3082. angle = 0.2922;
  3083. name = "San Fierro police deparment";
  3084. }
  3085. case INTERIOR_PD_BARBARA:{
  3086. x = 322.5014;
  3087. y = 303.6906;
  3088. z = 999.1484;
  3089. world = GetPlayerVirtualWorld(playerid);
  3090. interior = 5;
  3091. angle = 8.1747;
  3092. name = "Barbara's Love nest";
  3093. }
  3094. }
  3095. new target_player = GetGVarInt("goto_target", playerid);
  3096. DeleteGVar("goto_target", playerid);
  3097. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3098. }
  3099. else{dialogGotoInterior(playerid);}
  3100. }
  3101. case DIALOG_GOTO_HOUSE:{
  3102. if(response){
  3103. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[25 + 1];
  3104. switch(listitem){
  3105. case INTERIOR_HOUSE_GOLDEN:{
  3106. x = 2251.85;
  3107. y = -1138.16;
  3108. z = 1050.63;
  3109. world = GetPlayerVirtualWorld(playerid);
  3110. interior = 9;
  3111. angle = 167.3959;
  3112. name = "Golden Bed motel room";
  3113. }
  3114. case INTERIOR_HOUSE_HASHBURY:{
  3115. x = 2260.76;
  3116. y = -1210.45;
  3117. z = 1049.02;
  3118. world = GetPlayerVirtualWorld(playerid);
  3119. interior = 10;
  3120. angle = 266.88;
  3121. name = "Hashbury house";
  3122. }
  3123. case INTERIOR_HOUSE_JOHNSON:{
  3124. x = 2496.65;
  3125. y = -1696.55;
  3126. z = 1014.74;
  3127. world = GetPlayerVirtualWorld(playerid);
  3128. interior = 3;
  3129. angle = 179.2174;
  3130. name = "The Johnson house";
  3131. }
  3132. case INTERIOR_HOUSE_MADDDOGG:{
  3133. x = 1299.14;
  3134. y = -794.77;
  3135. z = 1084.00;
  3136. world = GetPlayerVirtualWorld(playerid);
  3137. interior = 5;
  3138. angle = 231.3418;
  3139. name = "Madd Doggs mansion";
  3140. }
  3141. case INTERIOR_HOUSE_RED:{
  3142. x = 2262.83;
  3143. y = -1137.71;
  3144. z = 1050.63;
  3145. world = GetPlayerVirtualWorld(playerid);
  3146. interior = 10;
  3147. angle = 266.88;
  3148. name = "Red Bed motel room";
  3149. }
  3150. case INTERIOR_HOUSE_VERDANT:{
  3151. x = 2365.42;
  3152. y = -1131.85;
  3153. z = 1050.88;
  3154. world = GetPlayerVirtualWorld(playerid);
  3155. interior = 8;
  3156. angle = 177.3947;
  3157. name = "Verdant Bluffs safehouse";
  3158. }
  3159. case INTERIOR_HOUSE_UNUSED:{
  3160. x = 2324.33;
  3161. y = -1144.79;
  3162. z = 1050.71;
  3163. world = GetPlayerVirtualWorld(playerid);
  3164. interior = 12;
  3165. angle = 269.0954;
  3166. name = "Unused safe house";
  3167. }
  3168. }
  3169. new target_player = GetGVarInt("goto_target", playerid);
  3170. DeleteGVar("goto_target", playerid);
  3171. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3172. }
  3173. else{dialogGotoInterior(playerid);}
  3174. }
  3175. case DIALOG_GOTO_SHOP:{
  3176. if(response){
  3177. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[25 + 1];
  3178. switch(listitem){
  3179. case INTERIOR_SHOP_TATTOO:{
  3180. x = -203.0764;
  3181. y = -24.1658;
  3182. z = 1002.2734;
  3183. world = GetPlayerVirtualWorld(playerid);
  3184. interior = 16;
  3185. angle = 252.8154;
  3186. name = "Tattoos";
  3187. }
  3188. case INTERIOR_SHOP_BURGER:{
  3189. x = 366.0248;
  3190. y = -73.3478;
  3191. z = 1001.5078;
  3192. world = GetPlayerVirtualWorld(playerid);
  3193. interior = 10;
  3194. angle = 292.0084;
  3195. name = "Burger Shot";
  3196. }
  3197. case INTERIOR_SHOP_PIZZA:{
  3198. x = 372.3520;
  3199. y = -131.6510;
  3200. z = 1001.4922;
  3201. world = GetPlayerVirtualWorld(playerid);
  3202. interior = 5;
  3203. angle = 354.2285;
  3204. name = "Well Stacked Pizza";
  3205. }
  3206. case INTERIOR_SHOP_CLUCKIN:{
  3207. x = 365.7158;
  3208. y = -9.8873;
  3209. z = 1001.8516;
  3210. world = GetPlayerVirtualWorld(playerid);
  3211. interior = 9;
  3212. angle = 160.528;
  3213. name = "Cluckin' Bell";
  3214. }
  3215. case INTERIOR_SHOP_CALIGULAS:{
  3216. x = 2233.8032;
  3217. y = 1712.2303;
  3218. z = 1011.7632;
  3219. world = GetPlayerVirtualWorld(playerid);
  3220. interior = 1;
  3221. angle = 184.3891;
  3222. name = "Caligulas Casino";
  3223. }
  3224. case INTERIOR_SHOP_CASINO:{
  3225. x = 1118.8878;
  3226. y = -10.2737;
  3227. z = 1002.0859;
  3228. world = GetPlayerVirtualWorld(playerid);
  3229. interior = 12;
  3230. angle = 165.8482;
  3231. name = "Casino (Redsands West)";
  3232. }
  3233. case INTERIOR_SHOP_4DRAGONS:{
  3234. x = 2016.2699;
  3235. y = 1017.7790;
  3236. z = 996.8750;
  3237. world = GetPlayerVirtualWorld(playerid);
  3238. interior = 10;
  3239. angle = 88.0055;
  3240. name = "4 Dragons Casino";
  3241. }
  3242. case INTERIOR_SHOP_DONUTS:{
  3243. x = 376.99;
  3244. y = -191.21;
  3245. z = 1000.63;
  3246. world = GetPlayerVirtualWorld(playerid);
  3247. interior = 17;
  3248. angle = 141.0245;
  3249. name = "Rusty Brown's donuts";
  3250. }
  3251. case INTERIOR_SHOP_RC:{
  3252. x = -2240.00;
  3253. y = 131.00;
  3254. z = 1035.40;
  3255. world = GetPlayerVirtualWorld(playerid);
  3256. interior = 6;
  3257. angle = 269.0954;
  3258. name = "Zero's RC shop";
  3259. }
  3260. case INTERIOR_SHOP_PUMP:{
  3261. x = 681.66;
  3262. y = -453.32;
  3263. z = -25.61;
  3264. world = GetPlayerVirtualWorld(playerid);
  3265. interior = 1;
  3266. angle = 166.166;
  3267. name = "The Welcome Pump";
  3268. }
  3269. }
  3270. new target_player = GetGVarInt("goto_target", playerid);
  3271. DeleteGVar("goto_target", playerid);
  3272. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3273. }
  3274. else{dialogGotoInterior(playerid);}
  3275. }
  3276. case DIALOG_GOTO_STADIA:{
  3277. if(response){
  3278. new Float:x, Float:y, Float:z, world, interior, Float:angle, name[25 + 1];
  3279. switch(listitem){
  3280. case INTERIOR_STADIUM_BLOODBOWL:{
  3281. x = -1394.20;
  3282. y = 987.62;
  3283. z = 1023.96;
  3284. world = GetPlayerVirtualWorld(playerid);
  3285. interior = 15;
  3286. angle = 0.7013;
  3287. name = "Bloodbowl Stadium";
  3288. }
  3289. case INTERIOR_STADIUM_KICKSTART:{
  3290. x = -1410.72;
  3291. y = 1591.16;
  3292. z = 1052.53;
  3293. world = GetPlayerVirtualWorld(playerid);
  3294. interior = 14;
  3295. angle = 159.1255;
  3296. name = "Kickstart Stadium";
  3297. }
  3298. case INTERIOR_STADIUM_8TRACK:{
  3299. x = -1395.958;
  3300. y = -208.197;
  3301. z = 1051.170;
  3302. world = GetPlayerVirtualWorld(playerid);
  3303. interior = 7;
  3304. angle = 355.8576;
  3305. name = "8 Track Stadium";
  3306. }
  3307. case INTERIOR_STADIUM_DIRTBIKE:{
  3308. x = -1424.9319;
  3309. y = -664.5869;
  3310. z = 1059.8585;
  3311. world = GetPlayerVirtualWorld(playerid);
  3312. interior = 4;
  3313. angle = 170.9341;
  3314. name = "Dirtbike Stadium";
  3315. }
  3316. }
  3317. new target_player = GetGVarInt("goto_target", playerid);
  3318. DeleteGVar("goto_target", playerid);
  3319. teleportPlayer(target_player, x, y, z, world, interior, angle, name);
  3320. }
  3321. else{dialogGotoInterior(playerid);}
  3322. }
  3323. case DIALOG_CREATE_PICKUP:{
  3324. if(response){
  3325. switch(listitem){
  3326. case 0: ShowPlayerDialog(playerid, DIALOG_CREATE_FACTION_PICKUP, DIALOG_STYLE_LIST, "Faction types", "Police\nMedic\nFire fighter\nFederal Bureau of Investigation\nDepeartment of motorvehicles\nBroadcasting", "Select", "Cancel"); }
  3327. }
  3328. }
  3329. case DIALOG_CREATE_FACTION_PICKUP:{
  3330. if(response){
  3331. printf("Listitem: % i", listitem);
  3332. new Float:x, Float:y, Float:z;
  3333. GetPlayerPos(playerid, x, y, z);
  3334. new world = GetPlayerVirtualWorld(playerid);
  3335. new interior = GetPlayerInterior(playerid);
  3336. new pickupid = createDynamicPickup(1247, x, y, z, world, interior, listitem);
  3337. // Create pickup record
  3338. new pickup_query[127 + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_FLOAT + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + MAX_SQL_INTEGER + 1];
  3339. format(pickup_query, sizeof(pickup_query), "INSERT INTO pickup(object_id, pos_x, pos_y, pos_z, world_id, interior_id, type_id, pickup_id) VALUES (1247, '%f', '%f', '%f', %i, %i, %i, %i)", x, y, z, world, interior, listitem, pickupid);
  3340. sql_query(sqlHandle, pickup_query);
  3341. // Get pickup record ID
  3342. new id_query[44 + 1];
  3343. format(id_query, sizeof(id_query), "SELECT id FROM pickup WHERE pickup_id = %i", pickupid);
  3344. new Result:id_result = sql_query(sqlHandle, id_query);
  3345. new pickup_id = sql_get_field_assoc_int(id_result, "id");
  3346. new admin_message[21 + 4 + MAX_PLAYER_NAME + MAX_SQL_INTEGER + 1];
  3347. // Inform admins
  3348. listitem++; // To account for FACTION_NONE
  3349. printf("Listitem: % i", listitem);
  3350. switch(listitem){
  3351. case FACTION_POLICE: format(admin_message, sizeof(admin_message), "* [%i] %s created police faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3352. case FACTION_MEDIC: format(admin_message, sizeof(admin_message), "* [%i] %s created medic faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3353. case FACTION_FIRE: format(admin_message, sizeof(admin_message), "* [%i] %s created firefighter faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3354. case FACTION_SHERIFF: format(admin_message, sizeof(admin_message), "* [%i] %s created shariff faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3355. case FACTION_FBI: format(admin_message, sizeof(admin_message), "* [%i] %s created FBI faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3356. case FACTION_DMV: format(admin_message, sizeof(admin_message), "* [%i] %s created DMV faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3357. case FACTION_NEWS: format(admin_message, sizeof(admin_message), "* [%i] %s created broadcasting faction pickup: %i", playerid, getPlayerName(playerid), pickup_id);
  3358. default: return 0;
  3359. }
  3360. sendToAdmins(COLOR_NOTICE, admin_message);
  3361. DiscordEcho(admin_message, ADMIN_ECHO_CHANNEL);
  3362. }
  3363. }
  3364. case DIALOG_DUTY_PD:{ // TODO: Make DRY DUTY_ & _SKIN
  3365. if(response){
  3366. // TODO: Check if has passport
  3367. switch(GetGVarInt("job", playerid)){
  3368. case JOB_NONE:{
  3369. // TODO: Check for crimes, warrents, etc
  3370. ShowPlayerDialog(playerid, DIALOG_POLICE_SKIN, DIALOG_STYLE_TABLIST, "Police skins", "Police Officer\tMale\tLS\nPolice Officer\tMale\tSF\nMotorbike Cop\tMale\tLS\nPolice Officer (Without gun holster)\tMale\tLS\nPolice Officer (Without gun holster)\tMale\tSF\nPolice Officer\tFemale\tLS\nPolice Officer\tFemale\tSF", "Duty", "Cancel");
  3371. }
  3372. case JOB_POLICE:{
  3373. // Get skin from character record
  3374. new character_query[42 + MAX_SQL_INTEGER + 1];
  3375. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3376. new Result:id_result = sql_query(sqlHandle, character_query);
  3377. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3378. setPlayerSkin(playerid, skin_id);
  3379. SetGVarInt("job", JOB_NONE, playerid);
  3380. SetPlayerColor(playerid, COLOR_WHITE);
  3381. ResetPlayerWeapons(playerid);
  3382. // TODO: get weaponskill fromddatabase and set it to player.
  3383. }
  3384. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3385. }
  3386. }
  3387. }
  3388. case DIALOG_POLICE_SKIN:{
  3389. if(response){
  3390. new skin;
  3391. switch(listitem){
  3392. case 0:{skin = 280;}
  3393. case 1:{skin = 281;}
  3394. case 2:{skin = 284;}
  3395. case 3:{skin = 300;}
  3396. case 4:{skin = 301;}
  3397. case 5:{skin = 306;}
  3398. case 6:{skin = 307;}
  3399. }
  3400. setPlayerSkin(playerid, skin);
  3401. SetGVarInt("job", JOB_POLICE, playerid);
  3402. SetPlayerColor(playerid, COLOR_POLICE);
  3403. SetPlayerSkillLevel(playerid, WEAPONSKILL_PISTOL, 1);
  3404. GivePlayerWeapon(playerid, 3, 1); // Baton
  3405. GivePlayerWeapon(playerid, 17, 10); // Teargas
  3406. GivePlayerWeapon(playerid, 22, 170); // 10 clips and a 9mm
  3407. }
  3408. }
  3409. case DIALOG_DUTY_MD:{
  3410. if(response){
  3411. // TODO: Check if has passport
  3412. switch(GetGVarInt("job", playerid)){
  3413. case JOB_NONE:{
  3414. // TODO: Check for crimes, warrents, etc
  3415. ShowPlayerDialog(playerid, DIALOG_MEDIC_SKIN, DIALOG_STYLE_TABLIST, "Paramedic skins", "Los Santos white\tMale\nLas Venturas blue\tMale\nSan Fierro green\tMale\nSan Fierro green\tFemale", "Duty", "Cancel");
  3416. }
  3417. case JOB_MEDIC:{
  3418. // Get skin from character record
  3419. new character_query[42 + MAX_SQL_INTEGER + 1];
  3420. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3421. new Result:id_result = sql_query(sqlHandle, character_query);
  3422. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3423. setPlayerSkin(playerid, skin_id);
  3424. SetGVarInt("job", JOB_NONE, playerid);
  3425. SetPlayerColor(playerid, COLOR_WHITE);
  3426. }
  3427. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3428. }
  3429. }
  3430. }
  3431. case DIALOG_MEDIC_SKIN:{
  3432. if(response){
  3433. new skin;
  3434. switch(listitem){
  3435. case 0:{skin = 274;}
  3436. case 1:{skin = 275;}
  3437. case 2:{skin = 276;}
  3438. case 3:{skin = 308;}
  3439. }
  3440. setPlayerSkin(playerid, skin);
  3441. SetGVarInt("job", JOB_MEDIC, playerid);
  3442. SetPlayerColor(playerid, COLOR_MEDIC);
  3443. }
  3444. }
  3445. case DIALOG_DUTY_FD:{
  3446. if(response){
  3447. // TODO: Check if has passport
  3448. switch(GetGVarInt("job", playerid)){
  3449. case JOB_NONE:{
  3450. // TODO: Check for crimes, warrents, etc
  3451. ShowPlayerDialog(playerid, DIALOG_FIRE_SKIN, DIALOG_STYLE_TABLIST, "Firefighter skins", "Los Santos green\tMale\nLas Venturas yellow\tMale\nSan Fierro black\tMale", "Duty", "Cancel");
  3452. }
  3453. case JOB_FIRE:{
  3454. // Get skin from character record
  3455. new character_query[42 + MAX_SQL_INTEGER + 1];
  3456. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3457. new Result:id_result = sql_query(sqlHandle, character_query);
  3458. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3459. setPlayerSkin(playerid, skin_id);
  3460. SetGVarInt("job", JOB_NONE, playerid);
  3461. SetPlayerColor(playerid, COLOR_WHITE);
  3462. ResetPlayerWeapons(playerid);
  3463. }
  3464. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3465. }
  3466. }
  3467. }
  3468. case DIALOG_FIRE_SKIN:{
  3469. if(response){
  3470. new skin;
  3471. switch(listitem){
  3472. case 0:{skin = 277;}
  3473. case 1:{skin = 278;}
  3474. case 2:{skin = 279;}
  3475. }
  3476. setPlayerSkin(playerid, skin);
  3477. SetGVarInt("job", JOB_FIRE, playerid);
  3478. SetPlayerColor(playerid, COLOR_FIRE);
  3479. GivePlayerWeapon(playerid, 42, 1); // Fire extinguisher
  3480. }
  3481. }
  3482. case DIALOG_DUTY_SD:{
  3483. if(response){
  3484. // TODO: Check if has passport
  3485. switch(GetGVarInt("job", playerid)){
  3486. case JOB_NONE:{
  3487. // TODO: Check for crimes, warrents, etc
  3488. ShowPlayerDialog(playerid, DIALOG_SHERIFF_SKIN, DIALOG_STYLE_TABLIST, "Sheriff skins", "Officer\tMale\tLV\nCounty sheriff\tMale\tCountryside\nDesert sheriff\tMale\tDesert\nOfficer (Without gun holster)\tMale\nOfficer\tFemale\nCounty sheriff (Without hat)\tMale\nDesert sheriff\tMale", "Duty", "Cancel");
  3489. }
  3490. case JOB_SHERIFF:{
  3491. // Get skin from character record
  3492. new character_query[42 + MAX_SQL_INTEGER + 1];
  3493. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3494. new Result:id_result = sql_query(sqlHandle, character_query);
  3495. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3496. setPlayerSkin(playerid, skin_id);
  3497. SetGVarInt("job", JOB_NONE, playerid);
  3498. SetPlayerColor(playerid, COLOR_WHITE);
  3499. // TODO restore weaponskill
  3500. ResetPlayerWeapons(playerid);
  3501. }
  3502. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3503. }
  3504. }
  3505. }
  3506. case DIALOG_SHERIFF_SKIN:{
  3507. if(response){
  3508. new skin;
  3509. switch(listitem){
  3510. case 0:{skin = 282;}
  3511. case 1:{skin = 283;}
  3512. case 2:{skin = 288;}
  3513. case 3:{skin = 302;}
  3514. case 4:{skin = 309;}
  3515. case 5:{skin = 310;}
  3516. case 6:{skin = 311;}
  3517. }
  3518. setPlayerSkin(playerid, skin);
  3519. SetGVarInt("job", JOB_SHERIFF, playerid);
  3520. SetPlayerColor(playerid, COLOR_SHERIFF);
  3521. SetPlayerSkillLevel(playerid, WEAPONSKILL_PISTOL, 1);
  3522. GivePlayerWeapon(playerid, 3, 1); // Baton
  3523. GivePlayerWeapon(playerid, 17, 10); // Teargas
  3524. GivePlayerWeapon(playerid, 22, 170); // 10 clips and a 9mm
  3525. }
  3526. }
  3527. case DIALOG_DUTY_FBI:{
  3528. if(response){
  3529. // TODO: Check if has passport
  3530. switch(GetGVarInt("job", playerid)){
  3531. case JOB_NONE:{
  3532. // TODO: Check for crimes, warrents, etc
  3533. ShowPlayerDialog(playerid, DIALOG_FBI_SKIN, DIALOG_STYLE_TABLIST, "Agent skins", "Caucasian MIB agent\tMale\nAfro-American MIB agent\tMale\nSWAT special forces\tMale\nFBI agent\tMale\nAfro-American bouncer\tMale\nCaucasian Bouncer\tMale\nOriental businesswoman\tFemale\nCaucasian businesswoman\tFemale", "Duty", "Cancel");
  3534. }
  3535. case JOB_FBI:{
  3536. // Get skin from character record
  3537. new character_query[42 + MAX_SQL_INTEGER + 1];
  3538. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3539. new Result:id_result = sql_query(sqlHandle, character_query);
  3540. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3541. setPlayerSkin(playerid, skin_id);
  3542. SetGVarInt("job", JOB_NONE, playerid);
  3543. SetPlayerColor(playerid, COLOR_WHITE);
  3544. ResetPlayerWeapons(playerid);
  3545. }
  3546. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3547. }
  3548. }
  3549. }
  3550. case DIALOG_FBI_SKIN:{
  3551. if(response){
  3552. new skin;
  3553. switch(listitem){
  3554. case 0:{skin = 165;}
  3555. case 1:{skin = 166;}
  3556. case 2:{skin = 258;}
  3557. case 3:{skin = 286;}
  3558. case 4:{skin = 163;}
  3559. case 5:{skin = 164;}
  3560. case 7:{skin = 141;}
  3561. case 8:{skin = 150;}
  3562. }
  3563. setPlayerSkin(playerid, skin);
  3564. SetGVarInt("job", JOB_FBI, playerid);
  3565. SetPlayerColor(playerid, COLOR_FBI);
  3566. GivePlayerWeapon(playerid, 23, 170); // 10 clips and a silenced 9mm
  3567. }
  3568. }
  3569. case DIALOG_DUTY_DMV:{
  3570. if(response){
  3571. // TODO: Check if has passport
  3572. switch(GetGVarInt("job", playerid)){
  3573. case JOB_NONE:{
  3574. // TODO: Check for crimes, warrents, etc
  3575. ShowPlayerDialog(playerid, DIALOG_DMV_SKIN, DIALOG_STYLE_TABLIST, "DMV skins", "Airport ground worker\tMale\nSecurity guard\tMale", "Duty", "Cancel");
  3576. }
  3577. case JOB_DMV:{
  3578. // Get skin from character record
  3579. new character_query[42 + MAX_SQL_INTEGER + 1];
  3580. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3581. new Result:id_result = sql_query(sqlHandle, character_query);
  3582. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3583. setPlayerSkin(playerid, skin_id);
  3584. SetGVarInt("job", JOB_NONE, playerid);
  3585. SetPlayerColor(playerid, COLOR_WHITE);
  3586. ResetPlayerWeapons(playerid);
  3587. }
  3588. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3589. }
  3590. }
  3591. }
  3592. case DIALOG_DMV_SKIN:{
  3593. if(response){
  3594. new skin;
  3595. switch(listitem){
  3596. case 0:{skin = 16;}
  3597. case 1:{skin = 71;}
  3598. }
  3599. setPlayerSkin(playerid, skin);
  3600. SetGVarInt("job", JOB_DMV, playerid);
  3601. SetPlayerColor(playerid, COLOR_DMV);
  3602. GivePlayerWeapon(playerid, 17, 10); // Teargas
  3603. }
  3604. }
  3605. case DIALOG_DUTY_NEWS:{
  3606. if(response){
  3607. // TODO: Check if has passport
  3608. switch(GetGVarInt("job", playerid)){
  3609. case JOB_NONE:{
  3610. // TODO: Check for crimes, warrents, etc
  3611. ShowPlayerDialog(playerid, DIALOG_DMV_SKIN, DIALOG_STYLE_TABLIST, "Network skins", "Hispanic businesswoman\nCaucasian Businesswoman\nBusinessman\nRich woman", "Duty", "Cancel");
  3612. }
  3613. case JOB_NEWS:{
  3614. // Get skin from character record
  3615. new character_query[42 + MAX_SQL_INTEGER + 1];
  3616. format(character_query, sizeof(character_query), "SELECT skin_id FROM character WHERE id = %i", GetGVarInt("character_id", playerid));
  3617. new Result:id_result = sql_query(sqlHandle, character_query);
  3618. new skin_id = sql_get_field_assoc_int(id_result, "skin_id");
  3619. setPlayerSkin(playerid, skin_id);
  3620. SetGVarInt("job", JOB_NONE, playerid);
  3621. SetPlayerColor(playerid, COLOR_WHITE);
  3622. ResetPlayerWeapons(playerid);
  3623. }
  3624. default:{SendClientMessage(playerid, COLOR_ERROR, "SERVER: You can not use this pickup as long as you are on another job.");}
  3625. }
  3626. }
  3627. }
  3628. case DIALOG_NEWS_SKIN:{
  3629. if(response){
  3630. new skin;
  3631. switch(listitem){
  3632. case 0:{skin = 148;}
  3633. case 1:{skin = 150;}
  3634. case 2:{skin = 187;}
  3635. case 3:{skin = 219;}
  3636. }
  3637. setPlayerSkin(playerid, skin);
  3638. SetGVarInt("job", JOB_NEWS, playerid);
  3639. SetPlayerColor(playerid, COLOR_NEWS);
  3640. GivePlayerWeapon(playerid, 43, 1); // Camera
  3641. }
  3642. }
  3643. }
  3644. return 0; // MUST return 0 here, just like OnPlayerCommandText.
  3645. }
  3646. public OnPlayerClickPlayer(playerid, clickedplayerid, source) // TODO for 0.0a
  3647. {
  3648. return 1;
  3649. }
  3650. public OnEnterExitModShop(playerid, enterexit, interiorid) // TODO for 0.0a
  3651. {
  3652. return 1;
  3653. }
  3654. public OnPlayerGiveDamage(playerid, damagedid, Float: amount, weaponid) // TODO for 0.0a
  3655. {
  3656. return 1;
  3657. }
  3658. public OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid) // TODO for 0.0a
  3659. {
  3660. return 1;
  3661. }
  3662. // discord-connector events
  3663. public DCC_OnMessageCreate(DCC_Message:message){
  3664. // Originating Discord channel
  3665. new DCC_Channel:channel;
  3666. DCC_GetMessageChannel(message, channel);
  3667. // Originating Discord user
  3668. new DCC_User:author;
  3669. DCC_GetMessageAuthor(message, author);
  3670. // Message content
  3671. new str[128 + 1]; // Orignal was 256
  3672. new command[32 + 1], params[128 + 1];
  3673. DCC_GetMessageContent(message, str);
  3674. sscanf(str, "s[32]s[128]", command, params); // This string is to small some times, and throws an error BROKEN TODO
  3675. // Ignore bots
  3676. new bool:isBot;
  3677. DCC_IsUserBot(author, isBot);
  3678. if(isBot){
  3679. return 1;
  3680. }
  3681. if(!strcmp(command, "!players")){
  3682. new players_string[14 + (2 * MAX_PLAYERS) + (MAX_PLAYER_NAME * MAX_PLAYERS) + 1] = "Online players:";
  3683. for(new playerid, a = GetMaxPlayers(); playerid < a; playerid++){
  3684. if(IsPlayerConnected(playerid)){
  3685. format(players_string, sizeof(players_string), "%s %s,", players_string, getPlayerName(playerid));
  3686. }
  3687. }
  3688. strdel(players_string, strlen(players_string), strlen(players_string)); // Delete trailing comma
  3689. DiscordSendChannelMessage(channel, players_string);
  3690. print("Should be sending players");
  3691. }
  3692. else if(!strcmp(command, "!ip")){
  3693. DiscordSendChannelMessage(channel, "ecrp.h0v1n8.nl:6666");
  3694. }
  3695. else{
  3696. if(channel == echoChannel){
  3697. sendToChat(-1, CHAT_GLOBAL, str, 0, author);
  3698. }
  3699. }
  3700. /*// Beyond this point, don't respond to commands on foreign guilds.
  3701. if(guild != homeGuild){
  3702. return 1;
  3703. }*/
  3704. // Beyond this point, only respond to privilaged channels.
  3705. if(channel != adminEchoChannel && channel != adminChannel && channel != managementChannel){
  3706. return 1;
  3707. }
  3708. // Test command.
  3709. if(!strcmp(command, "!test", true)){
  3710. DiscordSendChannelMessage(channel, "Works.");
  3711. print("Some said !test in the echo channel.");
  3712. }
  3713. return 1;
  3714. }
  3715. // Entrypoint
  3716. main(){
  3717. // Credits
  3718. print("\n*----------------------------------*");
  3719. print(" RPFW");
  3720. new message[21 + 20 + 1];
  3721. format(message, sizeof(message), " Role-play framework v%s", MODE_NAME);
  3722. print(message);
  3723. //printf("System load average: %f",loadavg()); // Linux only TODO: test
  3724. print("*----------------------------------*\n");
  3725. }