├── fxmanifest.lua
├── README.md
├── html
├── index.html
├── script.js
└── style.css
└── client.lua
/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 | -- Renzu Lock pick game
3 | -- MADE BY Renzuzu
4 | game 'gta5'
5 |
6 | lua54 'on'
7 | -- is_cfxv2 'yes'
8 | -- use_fxv2_oal 'true'
9 |
10 | ui_page {
11 | 'html/index.html',
12 | }
13 |
14 | client_scripts {
15 | "client.lua"
16 | }
17 |
18 | files {
19 | 'html/index.html',
20 | 'html/script.js',
21 | 'html/style.css',
22 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # renzu_lockgame
2 | # Simple Lockpicking Game
3 |
4 | # sample
5 | ```
6 | local options = {
7 | dict = "veh@break_in@0h@p_m_one@",
8 | name = "low_force_entry_ds",
9 | flag = 1,
10 | }
11 | local success = exports.renzu_lockgame:CreateGame(10,options)
12 |
13 | if success then
14 | print("success")
15 | else
16 | print("try again later")
17 | end
18 | ```
19 |
--------------------------------------------------------------------------------
/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Renzu LockGame
7 |
8 |
9 |
10 |
13 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/client.lua:
--------------------------------------------------------------------------------
1 | local open = false
2 | local done = false
3 | local result = nil
4 | RegisterNUICallback('close', function(data, cb)
5 | Wait(200)
6 | open = false
7 | SendNUIMessage({type = "reset", content = true})
8 | SetNuiFocus(false,false)
9 | SetNuiFocusKeepInput(false)
10 | done = true
11 | result = data.result or false
12 | Wait(2000)
13 | done = false
14 | end)
15 |
16 | function CreateGame(level,option, hide)
17 | if option == nil then
18 | option = {
19 | dict = "veh@break_in@0h@p_m_one@",
20 | name = "low_force_entry_ds",
21 | flag = 0
22 | }
23 | end
24 | local t = {
25 | level = level,
26 | hideshackle = hide or false
27 | }
28 | SetNuiFocus(true,false)
29 | local playinganimation = false
30 | SendNUIMessage({type = "create", table = t})
31 | CreateThread(function()
32 | FreezeEntityPosition(PlayerPedId(),true)
33 | local player = PlayerPedId()
34 | if option.scenario ~= nil then
35 | TaskStartScenarioInPlace(player, option.scenario, 0, true)
36 | playinganimation = true
37 | else
38 | if option.dict ~= nil and option.name ~= nil then
39 |
40 | if option.flag == nil then
41 | option.flag = 1
42 | end
43 | playinganimation = true
44 | RequestAnimDict( option.dict )
45 | while not HasAnimDictLoaded(option.dict) do Citizen.Wait(0) end
46 | RequestAnimDict( option.dict )
47 | local player = PlayerPedId()
48 | while not HasAnimDictLoaded(option.dict) do Citizen.Wait(0) end
49 | while result == nil do Wait(1000) TaskPlayAnim(player,option.dict, option.name, 2.0, 2.0, -1, option.flag, 1, false, false, false) end
50 | end
51 | end
52 | end)
53 | while result == nil do Wait(100) end
54 | Wait(1500)
55 | local player = PlayerPedId()
56 | FreezeEntityPosition(PlayerPedId(),false)
57 | local res = result
58 | result = nil
59 | done = true
60 | ClearPedTasks(player)
61 | Wait(500)
62 | done = false
63 | return res
64 | end
65 |
66 | exports('CreateGame', function(seconds,fa,o,hide)
67 | return CreateGame(seconds,fa,o,hide)
68 | end)
69 |
70 | RegisterCommand('lockgame', function(source, args, rawCommand) -- demo
71 | local o = {
72 | --scenario = 'WORLD_HUMAN_AA_COFFEE',
73 | dict = "veh@break_in@0h@p_m_one@",
74 | name = "low_force_entry_ds",
75 | flag = 1,
76 | }
77 | local prog = exports.renzu_lockgame:CreateGame(10,o)
78 | end)
--------------------------------------------------------------------------------
/html/script.js:
--------------------------------------------------------------------------------
1 | // config
2 | baseSpeed = 0.01;
3 | notchWidth = 0.1;
4 | linePosition = 0
5 | notchPosition = 0
6 | clockwise = 0
7 | //end config
8 |
9 | function setColor(color) {
10 | $("#shackle, #lock").css({"border-color": 'rgb(44 52 66)'});
11 | }
12 | function newNotch() {
13 | notchPosition = (((Math.random() * 0.75 * Math.PI) + 0.25 * Math.PI) * ((clockwise * 2) - 1)) + linePosition;
14 | $("#notch-dial").css({"-webkit-transform": "rotate(" + notchPosition + "rad)"});
15 | $("#notch-dial").css({"-moz-transform": "rotate(" + notchPosition + "rad)"});
16 | $("#notch-dial").css({"transform": "rotate(" + notchPosition + "rad)"});
17 | $("#notch").show();
18 | $("#notch").toggleClass("appear-b");
19 | }
20 | function setStatus(newStatus) {
21 | status = newStatus;
22 | switch (newStatus) {
23 | case "start":
24 | if (level < 10) setColor("green");
25 | else if (level < 20) setColor("violet");
26 | else if (level < 30) setColor("orange");
27 | else if (level < 40) setColor("blue");
28 | else setColor("olive");
29 | setCount(level);
30 | linePosition = 0;
31 | clockwise = true;
32 | newNotch();
33 | $("body").removeClass("fail");
34 | break;
35 | case "move":
36 | break;
37 | case "fail":
38 | close()
39 | document.getElementById("loadingbar").style.display = 'none';
40 | window.location.reload(false);
41 | $("#notch").hide();
42 | $("body").addClass("fail");
43 | break;
44 | case "win":
45 | $("#notch").hide();
46 | $("body").addClass("next");
47 | $("#shackle").addClass("unlock");
48 | close(true)
49 | setTimeout(function() {
50 | // setLevel(level + 1);
51 | // setStatus("start");
52 | $("#shackle").removeClass("unlock");
53 | document.getElementById("loadingbar").style.display = 'none';
54 | window.location.reload(false);
55 | }, 1000);
56 | setTimeout(function() {
57 | $("body").removeClass("next");
58 | }, 2000);
59 | break;
60 | }
61 | }
62 | function setCount(newCount) {
63 | count = newCount;
64 | $("#lock").text(count);
65 | }
66 | function setLevel(newLevel) {
67 | level = newLevel;
68 | $("#level").text(level);
69 | }
70 | function click() {
71 | switch (status) {
72 | case "start":
73 | setStatus("move")
74 | break;
75 | case "move":
76 | if (Math.abs(Math.atan2(Math.sin(linePosition - notchPosition), Math.cos(linePosition - notchPosition))) < notchWidth) {
77 | setCount(count - 1);
78 | if (count == 0) {
79 | setStatus("win");
80 | }
81 | else {
82 | clockwise = !clockwise;
83 | newNotch();
84 | }
85 | }
86 | else {
87 | setStatus("fail");
88 | }
89 | break;
90 | case "fail":
91 | setStatus("start");
92 | break;
93 | case "win":
94 | setStatus("start");
95 | break;
96 | }
97 | }
98 | function step() {
99 | if (status == "move") linePosition += baseSpeed * (clockwise * 2 - 1);
100 | $("#line-dial").css({"-webkit-transform": "rotate(" + linePosition + "rad)"});
101 | $("#line-dial").css({"-moz-transform": "rotate(" + linePosition + "rad)"});
102 | $("#line-dial").css({"transform": "rotate(" + linePosition + "rad)"});
103 | if ((Math.atan2(Math.sin(linePosition - notchPosition), Math.cos(linePosition - notchPosition))) * (clockwise * 2 - 1) > notchWidth) setStatus("fail");
104 | window.requestAnimationFrame(step);
105 | }
106 |
107 | function close(result) {
108 | var xhr = new XMLHttpRequest();
109 | xhr.open("POST", 'https://renzu_lockgame/close', true);
110 | xhr.setRequestHeader('Content-Type', 'application/json');
111 | xhr.send(JSON.stringify({result:result}));
112 | }
113 | window.requestAnimationFrame(step);
114 | window.addEventListener("mousedown", click);
115 | window.addEventListener("touchstart", function(event) {
116 | event.preventDefault();
117 | click();
118 | });
119 | window.addEventListener("keydown", click);
120 |
121 | var current = undefined
122 | window.addEventListener('message', function (table) {
123 | let event = table.data;
124 | if (event.type == 'create') {
125 | if (event.table.hideshackle) {
126 | document.getElementById("shackle").style.display = 'none';
127 | }
128 | document.getElementById("loadingbar").style.display = 'block';
129 | setLevel(event.table.level || 10)
130 | setStatus("start");
131 | }
132 | if (event.type == 'reset') {
133 | document.getElementById("loadingbar").style.display = 'none';
134 | window.location.reload(false);
135 | }
136 | });
137 |
138 | $(document).on('keydown', function(event) {
139 | switch(event.keyCode) {
140 | case 27: // ESC
141 | setTimeout(function(){ window.location.reload(false); }, 500);
142 | close()
143 | break;
144 | case 9: // TAB
145 | break;
146 | case 17: // TAB
147 | break;
148 | }
149 | });
--------------------------------------------------------------------------------
/html/style.css:
--------------------------------------------------------------------------------
1 | $line: hsl(343, 80%, 54%);
2 | $notch: hsl(48, 83%, 59%);
3 | $fail: hsl(0, 64%, 61%);
4 | @-webkit-keyframes appear-a {
5 | from {
6 | transform: scale(0);
7 | }
8 | to {
9 | transform: scale(1);
10 | }
11 | }
12 | @keyframes appear-a {
13 | from {
14 | transform: scale(0);
15 | }
16 | to {
17 | transform: scale(1);
18 | }
19 | }
20 | @-webkit-keyframes appear-b {
21 | from {
22 | transform: scale(0);
23 | }
24 | to {
25 | transform: scale(1);
26 | }
27 | }
28 | @keyframes appear-b {
29 | from {
30 | transform: scale(0);
31 | }
32 | to {
33 | transform: scale(1);
34 | }
35 | }
36 | @-webkit-keyframes fail {
37 | 0% {
38 | transform: rotate(0);
39 | }
40 | 25% {
41 | transform: rotate(-2deg);
42 | }
43 | 50% {
44 | transform: rotate(0);
45 | }
46 | 75% {
47 | transform: rotate(2deg);
48 | }
49 | 100% {
50 | transform: rotate(0);
51 | }
52 | }
53 | @keyframes fail {
54 | 0% {
55 | transform: rotate(0);
56 | }
57 | 25% {
58 | transform: rotate(-2deg);
59 | }
60 | 50% {
61 | transform: rotate(0);
62 | }
63 | 75% {
64 | transform: rotate(2deg);
65 | }
66 | 100% {
67 | transform: rotate(0);
68 | }
69 | }
70 | @-webkit-keyframes next {
71 | 0% {
72 | transform: translateX(0);
73 | }
74 | 25% {
75 | transform: translateX(0);
76 | }
77 | 49.8% {
78 | opacity: 1;
79 | }
80 | 49.9% {
81 | opacity: 0;
82 | transform: translateX(-100%);
83 | }
84 | 50.1% {
85 | opacity: 0;
86 | transform: translateX(100%);
87 | }
88 | 50.2% {
89 | opacity: 1;
90 | }
91 | 75% {
92 | transform: translateX(0);
93 | }
94 | 100% {
95 | transform: translateX(0);
96 | }
97 | }
98 | @keyframes next {
99 | 0% {
100 | transform: translateX(0);
101 | }
102 | 25% {
103 | transform: translateX(0);
104 | }
105 | 49.8% {
106 | opacity: 1;
107 | }
108 | 49.9% {
109 | opacity: 0;
110 | transform: translateX(-100%);
111 | }
112 | 50.1% {
113 | opacity: 0;
114 | transform: translateX(100%);
115 | }
116 | 50.2% {
117 | opacity: 1;
118 | }
119 | 75% {
120 | transform: translateX(0);
121 | }
122 | 100% {
123 | transform: translateX(0);
124 | }
125 | }
126 | @-webkit-keyframes unlock {
127 | from {
128 | transform: translateY(0);
129 | }
130 | to {
131 | transform: translateY(-64px);
132 | }
133 | }
134 | @keyframes unlock {
135 | from {
136 | transform: translateY(0);
137 | }
138 | to {
139 | transform: translateY(-64px);
140 | }
141 | }
142 | html, body {
143 | height: 100%;
144 | margin: 0;
145 | }
146 |
147 | body {
148 | display: flex;
149 | flex-direction: column;
150 | align-items: center;
151 | justify-content: center;
152 | font-family: sans-serif;
153 | min-width: 352px;
154 | transition: background-color 0.5s;
155 | overflow: hidden;
156 | }
157 |
158 | * {
159 | -webkit-user-select: none;
160 | -moz-user-select: none;
161 | -ms-user-select: none;
162 | user-select: none;
163 | }
164 |
165 | .fail {
166 | -webkit-animation: fail 0.5s ease-in-out;
167 | animation: fail 0.5s ease-in-out;
168 | background: #db5c5c !important;
169 | }
170 |
171 | .next {
172 | -webkit-animation: next 2s ease-in-out;
173 | animation: next 2s ease-in-out;
174 | }
175 |
176 | .unlock {
177 | -webkit-animation: unlock 0.5s ease-in-out forwards;
178 | animation: unlock 0.5s ease-in-out forwards;
179 | }
180 |
181 | #label {
182 | text-transform: uppercase;
183 | font-size: 36px;
184 | height: 128px;
185 | color: rgba(255, 255, 255, 0.5);
186 | }
187 |
188 | #shackle {
189 | height: 128px;
190 | width: 92px;
191 | border: 48px solid;
192 | border-bottom-color: transparent !important;
193 | border-radius: 92px 92px 0 0;
194 | margin-bottom: -64px;
195 | opacity: 0.6;
196 | margin: 0 auto -64px auto;
197 | }
198 |
199 | #lock {
200 | height: 192px;
201 | width: 192px;
202 | border: 48px solid;
203 | border-radius: 50%;
204 | line-height: 192px;
205 | text-align: center;
206 | font-size: 128px;
207 | color: rgba(255, 255, 255, 0.5);
208 | }
209 |
210 | .dial {
211 | position: absolute;
212 | height: 288px;
213 | width: 288px;
214 | display: flex;
215 | flex-direction: column;
216 | align-items: center;
217 | justify-content: top;
218 | }
219 |
220 | #line {
221 | margin: 6px;
222 | height: 36px;
223 | width: 12px;
224 | border-radius: 4px;
225 | background: #d8d8d8;
226 | }
227 |
228 | #notch {
229 | margin: 10px;
230 | height: 28px;
231 | width: 28px;
232 | border-radius: 50%;
233 | background: #319ddc;
234 | }
235 |
236 | .appear-a {
237 | -webkit-animation: appear-a 0.1s;
238 | animation: appear-a 0.1s;
239 | }
240 |
241 | .appear-b {
242 | -webkit-animation: appear-b 0.1s !important;
243 | animation: appear-b 0.1s !important;
244 | }
--------------------------------------------------------------------------------