@fruit-pie/quicksave 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +164 -74
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -962,12 +962,12 @@ ${r(y.hello)}`;
962
962
  createReads: g.filter((e) => _.has(e))
963
963
  }
964
964
  };
965
- }, H = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABWElEQVR4nM2VS3LCMAyGvew9ePXBIXoJLpI7dF9KIVDgGqw5RfPY9CY144CKKiJHsglh8U2UzNj/ZyESY/Z7AzwYcxNwJg23N4IXyLKsAi/I8/wPd18URQWu4b4sy4tAeJYkiUwAh9IaaBJwV0ywQN3p67qAQ+np1QL0tFwHfAJRHQAJ/BPQ1tP6qgJ1MwDXugHEdfQQdvY3xBLOFNsGwu5zfy8iCP+1byp+vl/FuP3T6cBu0/F/CY2AJjBKwFrDbsIhF3iRCWAJHGQnkwpaN4mAwEYj4LgIPeGrvQKL50CBhlCpwFojgMOlApyEWAAWgEAorMD8SSYAi7Qd2DUIfHUu8PnYnsAuVkDz4gmdAbUAne7YDqxmI7kAlfDVvvDWBHCoVGA5G+oE6CxwodJvwfIjQOCaX8MogRjOAgNeoG1cuJNgBRbvPYb+memRVMwxFII77QChyj4ABNYZj7JHZ24AAAAASUVORK5CYII=", U = 8, W = {
965
+ }, H = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABWElEQVR4nM2VS3LCMAyGvew9ePXBIXoJLpI7dF9KIVDgGqw5RfPY9CY144CKKiJHsglh8U2UzNj/ZyESY/Z7AzwYcxNwJg23N4IXyLKsAi/I8/wPd18URQWu4b4sy4tAeJYkiUwAh9IaaBJwV0ywQN3p67qAQ+np1QL0tFwHfAJRHQAJ/BPQ1tP6qgJ1MwDXugHEdfQQdvY3xBLOFNsGwu5zfy8iCP+1byp+vl/FuP3T6cBu0/F/CY2AJjBKwFrDbsIhF3iRCWAJHGQnkwpaN4mAwEYj4LgIPeGrvQKL50CBhlCpwFojgMOlApyEWAAWgEAorMD8SSYAi7Qd2DUIfHUu8PnYnsAuVkDz4gmdAbUAne7YDqxmI7kAlfDVvvDWBHCoVGA5G+oE6CxwodJvwfIjQOCaX8MogRjOAgNeoG1cuJNgBRbvPYb+memRVMwxFII77QChyj4ABNYZj7JHZ24AAAAASUVORK5CYII=", U = 8, W = 64, G = 3, K = {
966
966
  scale: .85,
967
967
  alpha: .6,
968
968
  swing: 8,
969
969
  pace: 800
970
- }, G = {
970
+ }, q = {
971
971
  state: "global.quicksave_state",
972
972
  room: "global.quicksave_room",
973
973
  x: "global.quicksave_x",
@@ -975,11 +975,12 @@ ${r(y.hello)}`;
975
975
  markerX: "global.quicksave_marker_x",
976
976
  markerY: "global.quicksave_marker_y",
977
977
  hasAnchor: "global.quicksave_has_anchor",
978
+ anchorRoom: "global.quicksave_anchor_room",
978
979
  anchorX: "global.quicksave_anchor_x",
979
980
  anchorY: "global.quicksave_anchor_y",
980
981
  applying: "global.quicksave_applying",
981
982
  carried: (e) => `global.quicksave_carried${e}`
982
- }, K = function(e, t) {
983
+ }, J = function(e, t) {
983
984
  let { players: n, carried: r, createReads: i, positionWrites: a, loads: o } = t, s = e.scratchPath("state.txt"), c = e.resource.sprite.create("save", { origin: {
984
985
  x: 16,
985
986
  y: 16
@@ -1008,34 +1009,36 @@ return global.quicksave_grounded;`
1008
1009
  file_text_writeln(qs_file);`, u = (e) => `qs_kind = file_text_read_string(qs_file); file_text_readln(qs_file);
1009
1010
  if (qs_kind == "s") ${e} = file_text_read_string(qs_file); else ${e} = file_text_read_real(qs_file);
1010
1011
  file_text_readln(qs_file);`, d = [
1011
- G.state,
1012
- G.room,
1013
- G.x,
1014
- G.y,
1015
- G.markerX,
1016
- G.markerY,
1017
- G.hasAnchor,
1018
- G.anchorX,
1019
- G.anchorY
1012
+ q.state,
1013
+ q.room,
1014
+ q.x,
1015
+ q.y,
1016
+ q.markerX,
1017
+ q.markerY,
1018
+ q.hasAnchor,
1019
+ q.anchorRoom,
1020
+ q.anchorX,
1021
+ q.anchorY
1020
1022
  ];
1021
1023
  e.resource.script.create({
1022
1024
  name: "persist",
1023
1025
  body: () => `var qs_file;
1024
- if (${G.state} == 0) {
1026
+ if (${q.state} == 0) {
1025
1027
  if (file_exists(${s})) file_delete(${s});
1026
1028
  exit;
1027
1029
  }
1028
1030
  qs_file = file_text_open_write(${s});
1029
1031
  ${d.map((e) => `file_text_write_real(qs_file, ${e}); file_text_writeln(qs_file);`).join("\n")}
1030
- ${r.map((e, t) => l(G.carried(t))).join("\n")}
1032
+ ${r.map((e, t) => l(q.carried(t))).join("\n")}
1031
1033
  file_text_close(qs_file);`
1032
1034
  }), e.resource.script.create({
1033
1035
  name: "reset",
1034
1036
  body: () => `${[
1035
1037
  ...d,
1036
- G.applying,
1037
- ...r.map((e, t) => G.carried(t))
1038
- ].map((e) => `${e} = 0;`).join("\n")}`
1038
+ q.applying,
1039
+ ...r.map((e, t) => q.carried(t))
1040
+ ].map((e) => `${e} = 0;`).join("\n")}
1041
+ ${q.anchorRoom} = -1;`
1039
1042
  }), e.resource.script.create({
1040
1043
  name: "restore",
1041
1044
  body: ({ call: e }) => `var qs_file, qs_kind;
@@ -1043,61 +1046,76 @@ ${e("reset")};
1043
1046
  if (!file_exists(${s})) exit;
1044
1047
  qs_file = file_text_open_read(${s});
1045
1048
  ${d.map((e) => `${e} = file_text_read_real(qs_file); file_text_readln(qs_file);`).join("\n")}
1046
- ${r.map((e, t) => u(G.carried(t))).join("\n")}
1049
+ ${r.map((e, t) => u(q.carried(t))).join("\n")}
1047
1050
  file_text_close(qs_file);`
1051
+ }), e.resource.script.create({
1052
+ name: "atAnchor",
1053
+ args: ["who", "checkRoom"],
1054
+ body: ({ a: e }) => `if (!${q.hasAnchor}) return 0;
1055
+ if (${e.checkRoom} && ${q.anchorRoom} >= 0 && ${q.anchorRoom} != room) return 0;
1056
+ if (abs(${e.who}.x - ${q.anchorX}) > ${U}) return 0;
1057
+ if (abs(${e.who}.y - ${q.anchorY}) > ${U}) return 0;
1058
+ return 1;`
1059
+ });
1060
+ let f = i.map((e) => `if (global.${e} != ${q.carried(r.indexOf(e))}) qs_rebuild = 1;`).join("\n");
1061
+ e.resource.script.create({
1062
+ name: "apply",
1063
+ args: ["who", "inPlace"],
1064
+ body: ({ a: e }) => `var qs_rebuild;
1065
+ ${q.applying} = 1;
1066
+ qs_rebuild = 0;
1067
+ ${f}
1068
+ ${r.map((e, t) => `global.${e} = ${q.carried(t)};`).join("\n")}
1069
+ if (${e.inPlace} == 0 || room != ${q.room}) room_goto(${q.room});
1070
+ with (${e.who}) {
1071
+ if (qs_rebuild) event_perform(ev_create, 0);
1072
+ x = ${q.x};
1073
+ y = ${q.y};
1074
+ xprevious = x;
1075
+ yprevious = y;
1076
+ hspeed = 0;
1077
+ vspeed = 0;
1078
+ }
1079
+ ${q.applying} = 0;`
1048
1080
  });
1049
1081
  for (let t of a) e.resource.script.insert({
1050
1082
  at: t,
1051
1083
  place: "after",
1052
1084
  body: ({ call: e, send: t }) => `
1053
1085
  var qs_player;
1054
- if (!${G.applying}) {
1086
+ if (!${q.applying}) {
1055
1087
  qs_player = ${e("player")};
1056
1088
  if (qs_player != noone) {
1057
- ${G.anchorX} = qs_player.x;
1058
- ${G.anchorY} = qs_player.y;
1059
- ${G.hasAnchor} = 1;
1089
+ ${q.anchorX} = qs_player.x;
1090
+ ${q.anchorY} = qs_player.y;
1091
+ ${q.anchorRoom} = room;
1092
+ ${q.hasAnchor} = 1;
1060
1093
  }
1061
- if (${G.state} != 0) {
1062
- ${G.state} = 0;
1094
+ if (${q.state} != 0) {
1095
+ ${q.state} = 0;
1063
1096
  ${t("cleared", "\"a real save\"")}
1064
1097
  }
1065
1098
  ${e("persist")};
1066
1099
  }
1067
1100
  `
1068
1101
  });
1069
- let f = i.map((e) => `if (global.${e} != ${G.carried(r.indexOf(e))}) qs_rebuild = 1;`).join("\n ");
1070
- for (let t of o) e.resource.script.hook(t, ({ original: e, call: n, send: i }) => `
1071
- var qs_result, qs_player, qs_near, qs_rebuild;
1102
+ for (let t of o) e.resource.script.hook(t, ({ original: e, call: n, send: r }) => `
1103
+ var qs_result, qs_player;
1072
1104
  qs_result = ${e.call()};
1073
1105
  qs_player = ${n("player")};
1074
1106
  if (qs_player != noone) {
1075
- qs_near = ${G.hasAnchor}
1076
- && abs(qs_player.x - ${G.anchorX}) <= ${U}
1077
- && abs(qs_player.y - ${G.anchorY}) <= ${U};
1078
- if (${G.state} == 1 && qs_near) {
1079
- ${G.applying} = 1;
1080
- qs_rebuild = 0;
1081
- ${f}
1082
- ${r.map((e, t) => `global.${e} = ${G.carried(t)};`).join("\n ")}
1083
- room_goto(${G.room});
1084
- with (qs_player) {
1085
- if (qs_rebuild) event_perform(ev_create, 0);
1086
- x = ${G.x};
1087
- y = ${G.y};
1088
- xprevious = x;
1089
- yprevious = y;
1090
- hspeed = 0;
1091
- vspeed = 0;
1092
- }
1093
- ${G.applying} = 0;
1094
- ${i("restored", `"by ${t}"`)}
1107
+ if (${q.state} == 1 && ${n("atAnchor", "qs_player", "0")}) {
1108
+ ${n("apply", "qs_player", "0")};
1109
+ ${r("restored", `"by ${t}"`)}
1110
+ } else if (${q.state} == 1) {
1111
+ ${r("missed", "\"a load landed away from this quicksave's save\"")}
1095
1112
  } else {
1096
- if (${G.state} == 1) ${i("dropped", "\"the game loaded a different save\"")}
1097
- ${G.state} = 0;
1098
- ${G.anchorX} = qs_player.x;
1099
- ${G.anchorY} = qs_player.y;
1100
- ${G.hasAnchor} = 1;
1113
+ if (${q.state} == 2) ${r("rearmed", `"by ${t}"`)}
1114
+ ${q.state} = 0;
1115
+ ${q.anchorX} = qs_player.x;
1116
+ ${q.anchorY} = qs_player.y;
1117
+ ${q.anchorRoom} = -1;
1118
+ ${q.hasAnchor} = 1;
1101
1119
  }
1102
1120
  ${n("persist")};
1103
1121
  }
@@ -1105,50 +1123,121 @@ file_text_close(qs_file);`
1105
1123
  `);
1106
1124
  e.resource.object.create({
1107
1125
  name: "quicksave",
1108
- vars: ["standing", "who"],
1126
+ vars: [
1127
+ "standing",
1128
+ "who",
1129
+ "seen",
1130
+ "settle",
1131
+ "lastId",
1132
+ "lastX",
1133
+ "lastY",
1134
+ "lastRoom"
1135
+ ],
1109
1136
  events: {
1110
1137
  create: ({ v: e, call: t }) => `
1111
1138
  ${t("restore")};
1112
1139
  ${e.standing} = 0;
1140
+ ${e.seen} = 0;
1141
+ ${e.settle} = 0;
1142
+ ${e.lastId} = noone;
1143
+ ${e.lastX} = 0;
1144
+ ${e.lastY} = 0;
1145
+ ${e.lastRoom} = -1;
1113
1146
  `,
1114
1147
  step: ({ v: e, call: t, send: n }) => `
1115
1148
  ${e.who} = ${t("player")};
1116
- // One behind the player: the only depth that means the same thing in every game.
1117
1149
  if (${e.who} != noone) depth = ${e.who}.depth + 1;
1118
- // Two steps, so bumping a ceiling mid-jump is not standing on it.
1119
1150
  if (${e.who} != noone && ${t("grounded", e.who)}) ${e.standing} += 1;
1120
1151
  else ${e.standing} = 0;
1121
1152
 
1122
1153
  if (keyboard_check_pressed(ord("X"))) {
1123
- if (${G.state} != 0) {
1154
+ if (${q.state} != 0) {
1124
1155
  ${n("refused", "\"a quicksave is already placed, or was cancelled until the next respawn\"")}
1125
- } else if (!${G.hasAnchor}) {
1156
+ } else if (!${q.hasAnchor}) {
1126
1157
  ${n("refused", "\"the game has not saved or loaded yet\"")}
1127
1158
  } else if (${e.standing} < 2) {
1128
1159
  ${n("refused", "\"not standing on anything\"")}
1129
1160
  } else {
1130
- ${G.room} = room;
1131
- ${G.x} = ${e.who}.x;
1132
- ${G.y} = ${e.who}.y;
1133
- ${G.markerX} = (${e.who}.bbox_left + ${e.who}.bbox_right) / 2;
1134
- ${G.markerY} = (${e.who}.bbox_top + ${e.who}.bbox_bottom) / 2;
1135
- ${r.map((e, t) => `${G.carried(t)} = global.${e};`).join("\n ")}
1136
- ${G.state} = 1;
1161
+ ${q.room} = room;
1162
+ ${q.x} = ${e.who}.x;
1163
+ ${q.y} = ${e.who}.y;
1164
+ ${q.markerX} = (${e.who}.bbox_left + ${e.who}.bbox_right) / 2;
1165
+ ${q.markerY} = (${e.who}.bbox_top + ${e.who}.bbox_bottom) / 2;
1166
+ ${r.map((e, t) => `${q.carried(t)} = global.${e};`).join("\n ")}
1167
+ ${q.state} = 1;
1137
1168
  ${t("persist")};
1138
- ${n("placed", `room_get_name(room) + " " + string(${G.x}) + "," + string(${G.y})`)}
1169
+ ${n("placed", `room_get_name(room) + " " + string(${q.x}) + "," + string(${q.y})`)}
1139
1170
  }
1140
1171
  }
1141
1172
 
1142
- if (keyboard_check_pressed(ord("C")) && ${G.state} == 1) {
1143
- ${G.state} = 2;
1173
+ if (keyboard_check_pressed(ord("C")) && ${q.state} == 1) {
1174
+ ${q.state} = 2;
1144
1175
  ${t("persist")};
1145
1176
  ${n("cancelled")}
1146
1177
  }
1178
+ `,
1179
+ endStep: ({ v: e, call: t, send: n }) => `
1180
+ var qs_who, qs_jump, qs_here;
1181
+ qs_who = ${t("player")};
1182
+
1183
+ if (qs_who != noone && ${q.hasAnchor} && ${q.anchorRoom} < 0) {
1184
+ if (${t("atAnchor", "qs_who", "0")}) ${q.anchorRoom} = room;
1185
+ }
1186
+
1187
+ qs_jump = 0;
1188
+ if (qs_who == noone) {
1189
+ ${e.seen} = 0;
1190
+ } else if (!${e.seen}) {
1191
+ qs_jump = 1;
1192
+ } else if (qs_who != ${e.lastId} || room != ${e.lastRoom}) {
1193
+ qs_jump = 1;
1194
+ } else if (abs(qs_who.x - ${e.lastX}) > ${W}
1195
+ || abs(qs_who.y - ${e.lastY}) > ${W}) {
1196
+ qs_jump = 1;
1197
+ }
1198
+
1199
+ if (qs_who != noone) {
1200
+ if (${e.settle} > 0) {
1201
+ ${e.settle} -= 1;
1202
+ if (${q.state} == 1 && room != ${q.room}) {
1203
+ ${t("apply", "qs_who", "0")};
1204
+ ${t("persist")};
1205
+ }
1206
+ }
1207
+
1208
+ if (qs_jump && ${q.state} != 0) {
1209
+ if (${t("atAnchor", "qs_who", "1")}) {
1210
+ qs_here = 0;
1211
+ if (${q.state} == 1) {
1212
+ qs_here = (room == ${q.room}
1213
+ && abs(qs_who.x - ${q.x}) <= ${U}
1214
+ && abs(qs_who.y - ${q.y}) <= ${U});
1215
+ }
1216
+ if (!qs_here) {
1217
+ if (${q.state} == 1) {
1218
+ ${t("apply", "qs_who", "1")};
1219
+ ${n("restored", "\"after a respawn\"")}
1220
+ ${t("persist")};
1221
+ ${e.settle} = ${G};
1222
+ } else if (${q.state} == 2) {
1223
+ ${q.state} = 0;
1224
+ ${t("persist")};
1225
+ ${n("rearmed", "\"after a respawn\"")}
1226
+ }
1227
+ }
1228
+ }
1229
+ }
1230
+ ${e.seen} = 1;
1231
+ ${e.lastId} = qs_who;
1232
+ ${e.lastX} = qs_who.x;
1233
+ ${e.lastY} = qs_who.y;
1234
+ ${e.lastRoom} = room;
1235
+ }
1147
1236
  `,
1148
1237
  draw: () => `
1149
- if (${G.state} == 1 && room == ${G.room} && ${c.id} >= 0) {
1150
- draw_sprite_ext(${c.id}, 0, ${G.markerX}, ${G.markerY}, ${W.scale}, ${W.scale},
1151
- ${W.swing} * sin(current_time / ${W.pace}), c_white, ${W.alpha});
1238
+ if (${q.state} == 1 && room == ${q.room} && ${c.id} >= 0) {
1239
+ draw_sprite_ext(${c.id}, 0, ${q.markerX}, ${q.markerY}, ${K.scale}, ${K.scale},
1240
+ ${K.swing} * sin(current_time / ${K.pace}), c_white, ${K.alpha});
1152
1241
  }
1153
1242
  `
1154
1243
  },
@@ -1161,13 +1250,14 @@ file_text_close(qs_file);`
1161
1250
  "placed",
1162
1251
  "cancelled",
1163
1252
  "restored",
1253
+ "rearmed",
1164
1254
  "cleared",
1165
- "dropped",
1255
+ "missed",
1166
1256
  "refused"
1167
1257
  ]) e.on(t, (e) => console.log(`[quicksave] ${t}${e ? `: ${e}` : ""}`));
1168
- }, q = T((e) => {
1258
+ }, Y = T((e) => {
1169
1259
  let t = V(e.content);
1170
- t.ok ? K(e, t.value) : console.warn(`[quicksave] this game is not supported: ${t.error}`);
1260
+ t.ok ? J(e, t.value) : console.warn(`[quicksave] this game is not supported: ${t.error}`);
1171
1261
  });
1172
1262
  //#endregion
1173
- export { q as default };
1263
+ export { Y as default };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@fruit-pie/quicksave",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
+ "displayName": "Quicksave",
4
5
  "description": "Save anywhere between two of the game's saves, without touching its save files.",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",