-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnfsu2-money-cheat.go
238 lines (196 loc) · 6.74 KB
/
nfsu2-money-cheat.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package main
//
// Cheat that edits the money stored within the Need For Speed Underground 2 save file.
//
import (
"bufio"
"encoding/binary"
"flag"
"fmt"
"io"
"os"
"strconv"
"strings"
"time"
)
const (
// NFSU2_MONEY_FILE_OFFSET: offset to where the money value is stored within the save file
NFSU2_MONEY_FILE_OFFSET int64 = 0xA16A
// program version
VERSION = "2.0"
)
// set to true if the program launched the TUI (text user interface); false otherwise
var using_tui bool = false
// PrintUsage: Print usage.
func PrintUsage() {
programName := os.Args[0]
fmt.Printf("Usage: %s <command> <save_file>\n", programName)
fmt.Println()
fmt.Println("Command:")
fmt.Println(" info Display how much money is stored within <save_file>")
fmt.Println(" edit Edit the money within <save_file>. The original <save_file> will be backed-up.")
fmt.Println(" help Print this help.")
fmt.Println()
fmt.Println("Examples:")
fmt.Println(" Edit the money available to 25000 within the given save file:")
fmt.Printf(" %s edit -m 25000 -f 'C:\\Users\\MyUserName\\bin\\Need For Speed Underground 2\\save\\NFS Underground 2\\MySaveFile'\n", programName)
fmt.Println()
fmt.Println(" Display the money within the given save file:")
fmt.Printf(" %s info -f 'C:\\Users\\MyUserName\\bin\\Need For Speed Underground 2\\save\\NFS Underground 2\\MySaveFile'\n", programName)
}
// PrintCurrentMoney: Print the currently stored money within the provided save file.
func PrintCurrentMoney(saveFile string) {
// open the save file
file, err := os.OpenFile(saveFile, os.O_RDONLY, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to open save file '%s': %s\n", saveFile, err)
Exit(1)
}
defer file.Close()
// moneyArr will hold the signed 32-bit integer (which represents the money store within the file)
moneyArr := make([]byte, 4)
// read the money stored in the save file
_, err = file.ReadAt(moneyArr, NFSU2_MONEY_FILE_OFFSET)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read the money currently stored within the save file '%s': %s\n", saveFile, err)
Exit(1)
}
// convert the money to int32 (as money in NFSU2 is stored as int32 - little endian)
moneyStored := int32(binary.LittleEndian.Uint32(moneyArr))
fmt.Printf("Money stored within save file = %d\n", moneyStored)
}
// BackupSaveFile: Backups up the provided save file.
func BackupSaveFile(origSaveFile string) {
dateTime := time.Now().Format(time.RFC3339)
backupFilePath := origSaveFile + "." + strings.ReplaceAll(dateTime, ":", ".") + ".backup"
// check if the save file is actually a file
origFileStat, err := os.Stat(origSaveFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to open save file '%s': %s\n", origSaveFile, err)
Exit(1)
}
if !origFileStat.Mode().IsRegular() {
fmt.Fprintf(os.Stderr, "The provided file is not a regular file '%s'\n", origSaveFile)
Exit(1)
}
// open the original (provided) save file
orig, err := os.Open(origSaveFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error occured while opening save file '%s': %s\n", origSaveFile, err)
Exit(1)
}
defer orig.Close()
// create the backup save file
backup, err := os.Create(backupFilePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error occured while creating backup save file '%s': %s\n", origSaveFile, err)
Exit(1)
}
defer backup.Close()
// copy the original into the backup
if _, err := io.Copy(backup, orig); err != nil {
fmt.Fprintf(os.Stderr, "Error occured while backuping the save file '%s': %s\n", origSaveFile, err)
Exit(1)
}
fmt.Println("Save file backed up at: ", backupFilePath)
}
// EditMoneySaveFile: Edit the money being stored within the provided save file.
func EditMoneySaveFile(money uint32, saveFile string) {
// open the save file
file, err := os.OpenFile(saveFile, os.O_RDWR, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to open save file '%s': %s\n", saveFile, err)
Exit(1)
}
defer file.Close()
// convert the money into an array of a 32 bit integer (little endian)
moneyArr := make([]byte, 4)
binary.LittleEndian.PutUint32(moneyArr, money)
// write the new money value within the save file
_, err = file.WriteAt(moneyArr, NFSU2_MONEY_FILE_OFFSET)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to write money into save file '%s': %s\n", saveFile, err)
Exit(1)
}
fmt.Printf("Placed %v money within your save. Enjoy!\n", money)
}
func Exit(exitCode int) {
if using_tui {
reader := bufio.NewReader(os.Stdin)
fmt.Println("~~ Press <enter> to exit ~~")
reader.ReadString('\n')
}
os.Exit(1)
}
func LaunchTui() {
using_tui = true
fmt.Println("----------------------------------------------------")
fmt.Println(" NEED FOR SPEED UNDERGROUND 2 - MONEY CHEAT ")
fmt.Println("----------------------------------------------------")
fmt.Println()
fmt.Println("Version:", VERSION)
fmt.Println("URL: ", "https://github.com/ram-on/nfsu2-money-cheat")
fmt.Println()
fmt.Println("Press <CTRL+C> to exit")
fmt.Println()
scanner := bufio.NewScanner(os.Stdin)
saveFilePath := ""
// get the save file path
for {
fmt.Print(" > Input full path of the NFSU2 Save File: ")
scanner.Scan()
saveFilePath = strings.TrimSpace(scanner.Text())
if len(saveFilePath) > 0 {
PrintCurrentMoney(saveFilePath)
break
}
}
fmt.Println()
// get the new money value and save it within the Save File
for {
fmt.Print(" > Input the money to be save in the Save File: ")
scanner.Scan()
moneyStr := strings.TrimSpace(scanner.Text())
if len(moneyStr) > 0 {
if money, err := strconv.ParseUint(moneyStr, 10, 32); err == nil {
EditMoneySaveFile(uint32(money), saveFilePath)
break
} else {
fmt.Println("Please input a valid number.")
}
}
}
}
func main() {
infoCmd := flag.NewFlagSet("info", flag.ExitOnError)
infoSaveFilePathVal := infoCmd.String("f", "", "NFSU2 save file path")
editCmd := flag.NewFlagSet("edit", flag.ExitOnError)
moneyVal := editCmd.Int("m", 0, "Money that will be saved in the provided save file. Minumum amount is 0. Maximum amount is 2147483647.")
editSaveFilePathVal := editCmd.String("f", "", "NFSU2 save file path")
if len(os.Args) == 1 {
LaunchTui()
} else if os.Args[1] == "info" {
infoCmd.Parse(os.Args[2:])
if *infoSaveFilePathVal == "" {
fmt.Fprintf(os.Stderr, "Save file not provided\n")
infoCmd.Usage()
Exit(1)
}
PrintCurrentMoney(*infoSaveFilePathVal)
} else if os.Args[1] == "edit" {
editCmd.Parse(os.Args[2:])
if *moneyVal < 0 {
fmt.Fprintf(os.Stderr, "Money cannot be < 0\n")
Exit(1)
}
if *editSaveFilePathVal == "" {
fmt.Fprintf(os.Stderr, "Save file not provided\n")
editCmd.Usage()
Exit(1)
}
BackupSaveFile(*editSaveFilePathVal)
EditMoneySaveFile(uint32(*moneyVal), *editSaveFilePathVal)
} else {
PrintUsage()
}
}