new post and updated /now

This commit is contained in:
2024-12-12 20:43:00 -05:00
parent 937b66e7c0
commit 3b3c0d6e5e
9 changed files with 260 additions and 468 deletions
+32
View File
@@ -0,0 +1,32 @@
{
"$ref": "#/definitions/blog",
"definitions": {
"blog": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"pubDate": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"$schema": {
"type": "string"
}
},
"required": [
"title",
"pubDate",
"tags"
],
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
+1
View File
@@ -0,0 +1 @@
export default new Map();
+1
View File
@@ -0,0 +1 @@
export default new Map();
+176
View File
@@ -0,0 +1,176 @@
declare module 'astro:content' {
interface Render {
'.mdx': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
components: import('astro').MDXInstance<{}>['components'];
}>;
}
}
declare module 'astro:content' {
export interface RenderResult {
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}
interface Render {
'.md': Promise<RenderResult>;
}
export interface RenderedContent {
html: string;
metadata?: {
imagePaths: Array<string>;
[key: string]: unknown;
};
}
}
declare module 'astro:content' {
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
export type CollectionKey = keyof AnyEntryMap;
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
export type ContentCollectionKey = keyof ContentEntryMap;
export type DataCollectionKey = keyof DataEntryMap;
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
ContentEntryMap[C]
>['slug'];
/** @deprecated Use `getEntry` instead. */
export function getEntryBySlug<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
// Note that this has to accept a regular string too, for SSR
entrySlug: E,
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
/** @deprecated Use `getEntry` instead. */
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
collection: C,
entryId: E,
): Promise<CollectionEntry<C>>;
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
collection: C,
filter?: (entry: CollectionEntry<C>) => entry is E,
): Promise<E[]>;
export function getCollection<C extends keyof AnyEntryMap>(
collection: C,
filter?: (entry: CollectionEntry<C>) => unknown,
): Promise<CollectionEntry<C>[]>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(entry: {
collection: C;
slug: E;
}): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(entry: {
collection: C;
id: E;
}): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
slug: E,
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(
collection: C,
id: E,
): E extends keyof DataEntryMap[C]
? string extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]> | undefined
: Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
/** Resolve an array of entry references from the same collection */
export function getEntries<C extends keyof ContentEntryMap>(
entries: {
collection: C;
slug: ValidContentEntrySlug<C>;
}[],
): Promise<CollectionEntry<C>[]>;
export function getEntries<C extends keyof DataEntryMap>(
entries: {
collection: C;
id: keyof DataEntryMap[C];
}[],
): Promise<CollectionEntry<C>[]>;
export function render<C extends keyof AnyEntryMap>(
entry: AnyEntryMap[C][string],
): Promise<RenderResult>;
export function reference<C extends keyof AnyEntryMap>(
collection: C,
): import('astro/zod').ZodEffects<
import('astro/zod').ZodString,
C extends keyof ContentEntryMap
? {
collection: C;
slug: ValidContentEntrySlug<C>;
}
: {
collection: C;
id: keyof DataEntryMap[C];
}
>;
// Allow generic `string` to avoid excessive type errors in the config
// if `dev` is not running to update as you edit.
// Invalid collection names will be caught at build time.
export function reference<C extends string>(
collection: C,
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
>;
type ContentEntryMap = {
};
type DataEntryMap = {
"blog": Record<string, {
id: string;
render(): Render[".md"];
slug: string;
body: string;
collection: "blog";
data: InferEntrySchema<"blog">;
rendered?: RenderedContent;
filePath?: string;
}>;
};
type AnyEntryMap = ContentEntryMap & DataEntryMap;
export type ContentConfig = typeof import("../src/content/config.js");
}
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
{
"_variables": {
"lastUpdateCheck": 1734053848141
}
}
+2 -465
View File
@@ -1,465 +1,2 @@
declare module 'astro:content' {
interface Render {
'.mdx': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}
declare module 'astro:content' {
interface Render {
'.md': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}
declare module 'astro:content' {
export { z } from 'astro/zod';
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
export type CollectionKey = keyof AnyEntryMap;
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
export type ContentCollectionKey = keyof ContentEntryMap;
export type DataCollectionKey = keyof DataEntryMap;
// This needs to be in sync with ImageMetadata
export type ImageFunction = () => import('astro/zod').ZodObject<{
src: import('astro/zod').ZodString;
width: import('astro/zod').ZodNumber;
height: import('astro/zod').ZodNumber;
format: import('astro/zod').ZodUnion<
[
import('astro/zod').ZodLiteral<'png'>,
import('astro/zod').ZodLiteral<'jpg'>,
import('astro/zod').ZodLiteral<'jpeg'>,
import('astro/zod').ZodLiteral<'tiff'>,
import('astro/zod').ZodLiteral<'webp'>,
import('astro/zod').ZodLiteral<'gif'>,
import('astro/zod').ZodLiteral<'svg'>,
import('astro/zod').ZodLiteral<'avif'>,
]
>;
}>;
type BaseSchemaWithoutEffects =
| import('astro/zod').AnyZodObject
| import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
| import('astro/zod').ZodDiscriminatedUnion<string, import('astro/zod').AnyZodObject[]>
| import('astro/zod').ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
type BaseSchema =
| BaseSchemaWithoutEffects
| import('astro/zod').ZodEffects<BaseSchemaWithoutEffects>;
export type SchemaContext = { image: ImageFunction };
type DataCollectionConfig<S extends BaseSchema> = {
type: 'data';
schema?: S | ((context: SchemaContext) => S);
};
type ContentCollectionConfig<S extends BaseSchema> = {
type?: 'content';
schema?: S | ((context: SchemaContext) => S);
};
type CollectionConfig<S> = ContentCollectionConfig<S> | DataCollectionConfig<S>;
export function defineCollection<S extends BaseSchema>(
input: CollectionConfig<S>
): CollectionConfig<S>;
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
ContentEntryMap[C]
>['slug'];
export function getEntryBySlug<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
// Note that this has to accept a regular string too, for SSR
entrySlug: E
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
collection: C,
entryId: E
): Promise<CollectionEntry<C>>;
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
collection: C,
filter?: (entry: CollectionEntry<C>) => entry is E
): Promise<E[]>;
export function getCollection<C extends keyof AnyEntryMap>(
collection: C,
filter?: (entry: CollectionEntry<C>) => unknown
): Promise<CollectionEntry<C>[]>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(entry: {
collection: C;
slug: E;
}): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(entry: {
collection: C;
id: E;
}): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
slug: E
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(
collection: C,
id: E
): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
/** Resolve an array of entry references from the same collection */
export function getEntries<C extends keyof ContentEntryMap>(
entries: {
collection: C;
slug: ValidContentEntrySlug<C>;
}[]
): Promise<CollectionEntry<C>[]>;
export function getEntries<C extends keyof DataEntryMap>(
entries: {
collection: C;
id: keyof DataEntryMap[C];
}[]
): Promise<CollectionEntry<C>[]>;
export function reference<C extends keyof AnyEntryMap>(
collection: C
): import('astro/zod').ZodEffects<
import('astro/zod').ZodString,
C extends keyof ContentEntryMap
? {
collection: C;
slug: ValidContentEntrySlug<C>;
}
: {
collection: C;
id: keyof DataEntryMap[C];
}
>;
// Allow generic `string` to avoid excessive type errors in the config
// if `dev` is not running to update as you edit.
// Invalid collection names will be caught at build time.
export function reference<C extends string>(
collection: C
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
>;
type ContentEntryMap = {
"blog": {
"2022/ask-the-darn-question.md": {
id: "2022/ask-the-darn-question.md";
slug: "2022/ask-the-darn-question";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/building-ghalldev-30.md": {
id: "2022/building-ghalldev-30.md";
slug: "2022/building-ghalldev-30";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/coding-with-depression.md": {
id: "2022/coding-with-depression.md";
slug: "2022/coding-with-depression";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/creating-a-dating-profile-with-ai.md": {
id: "2022/creating-a-dating-profile-with-ai.md";
slug: "2022/creating-a-dating-profile-with-ai";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/getting-out-of-your-comfort-zone.md": {
id: "2022/getting-out-of-your-comfort-zone.md";
slug: "2022/getting-out-of-your-comfort-zone";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/ileopard-a-retrospective.md": {
id: "2022/ileopard-a-retrospective.md";
slug: "2022/ileopard-a-retrospective";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/my-favorite-little-apps.md": {
id: "2022/my-favorite-little-apps.md";
slug: "2022/my-favorite-little-apps";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/my-macos-home-directory-overview.md": {
id: "2022/my-macos-home-directory-overview.md";
slug: "2022/my-macos-home-directory-overview";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/my-top-3-games-of-2022.md": {
id: "2022/my-top-3-games-of-2022.md";
slug: "2022/my-top-3-games-of-2022";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/nextjs-13-and-exploring-new-technologies.md": {
id: "2022/nextjs-13-and-exploring-new-technologies.md";
slug: "2022/nextjs-13-and-exploring-new-technologies";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2022/on-text-editors.md": {
id: "2022/on-text-editors.md";
slug: "2022/on-text-editors";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/an-update-on-my-ai-dating-profile.md": {
id: "2023/an-update-on-my-ai-dating-profile.md";
slug: "2023/an-update-on-my-ai-dating-profile";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/baldurs-gate-3-feels.md": {
id: "2023/baldurs-gate-3-feels.md";
slug: "2023/baldurs-gate-3-feels";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/default-apps-2023.md": {
id: "2023/default-apps-2023.md";
slug: "2023/default-apps-2023";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/finding-home-in-hyrule.md": {
id: "2023/finding-home-in-hyrule.md";
slug: "2023/finding-home-in-hyrule";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/handheld-gaming.md": {
id: "2023/handheld-gaming.md";
slug: "2023/handheld-gaming";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/journal-app-impressions.md": {
id: "2023/journal-app-impressions.md";
slug: "2023/journal-app-impressions";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/my-favorite-little-apps-part-2.md": {
id: "2023/my-favorite-little-apps-part-2.md";
slug: "2023/my-favorite-little-apps-part-2";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/my-gunpla-adventure.md": {
id: "2023/my-gunpla-adventure.md";
slug: "2023/my-gunpla-adventure";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/nostalgia.md": {
id: "2023/nostalgia.md";
slug: "2023/nostalgia";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/on-using-chat-gpt.md": {
id: "2023/on-using-chat-gpt.md";
slug: "2023/on-using-chat-gpt";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/questlogger-from-ios-to-mac.md": {
id: "2023/questlogger-from-ios-to-mac.md";
slug: "2023/questlogger-from-ios-to-mac";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/reflecting-on-building-my-first-app.md": {
id: "2023/reflecting-on-building-my-first-app.md";
slug: "2023/reflecting-on-building-my-first-app";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/reflecting-on-my-first-year-as-a-developer.md": {
id: "2023/reflecting-on-my-first-year-as-a-developer.md";
slug: "2023/reflecting-on-my-first-year-as-a-developer";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/thoughs-on-macos.md": {
id: "2023/thoughs-on-macos.md";
slug: "2023/thoughs-on-macos";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/using-json-for-data-storage.md": {
id: "2023/using-json-for-data-storage.md";
slug: "2023/using-json-for-data-storage";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2023/using-tailwind-with-mui-base.md": {
id: "2023/using-tailwind-with-mui-base.md";
slug: "2023/using-tailwind-with-mui-base";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/ai-and-creativity.md": {
id: "2024/ai-and-creativity.md";
slug: "2024/ai-and-creativity";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/am-i-switching-to-zed.md": {
id: "2024/am-i-switching-to-zed.md";
slug: "2024/am-i-switching-to-zed";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/doctor-type-love.md": {
id: "2024/doctor-type-love.md";
slug: "2024/doctor-type-love";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/finishing-stuff.md": {
id: "2024/finishing-stuff.md";
slug: "2024/finishing-stuff";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/my-backup-solution.md": {
id: "2024/my-backup-solution.md";
slug: "2024/my-backup-solution";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/my-five-formative-games.md": {
id: "2024/my-five-formative-games.md";
slug: "2024/my-five-formative-games";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/my-terminal-setup.md": {
id: "2024/my-terminal-setup.md";
slug: "2024/my-terminal-setup";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/notes-on-these-airpods.md": {
id: "2024/notes-on-these-airpods.md";
slug: "2024/notes-on-these-airpods";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/playing-on-easy-mode.md": {
id: "2024/playing-on-easy-mode.md";
slug: "2024/playing-on-easy-mode";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/ramblings-on-the-macintosh.md": {
id: "2024/ramblings-on-the-macintosh.md";
slug: "2024/ramblings-on-the-macintosh";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"2024/rip-homepod-mini.md": {
id: "2024/rip-homepod-mini.md";
slug: "2024/rip-homepod-mini";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
};
};
type DataEntryMap = {
};
type AnyEntryMap = ContentEntryMap & DataEntryMap;
type ContentConfig = typeof import("../src/content/config");
}
/// <reference types="astro/client" />
/// <reference path="content.d.ts" />
@@ -0,0 +1,39 @@
---
title: 'My Top 3 Games of 2024'
pubDate: '2024-12-12'
tags: ['Gaming']
---
Back in December 2022, I wrote about [my top 3 games of that year](/posts/2022/my-top-3-games-of-2022/) in what I hoped would be a yearly tradition. For 2023, Tears of the Kingdom and Baldurs Gate 3 blew me away that I couldnt fathom selecting a third game that stood up to them. This year however, Im returning to the originally envisioned format for my top 3 games of 2024.
One of my regrets from the 2022 post was that I didnt go into very much detail as to why I liked the games, so this time around I wanted to make sure to go more in-depth (but not too in-depth). So, over the course of the year, Ive kept a journal of every game I finished in 2024, and wrote down what I thought about it while the experience was still fresh in my mind. I chose this list by re-reading my journal and picking the 3 games that, upon reflection, still resonate with me in the same way.
### Star Wars: Outlaws
Ok, this is a controversial pick, but, despite its many flaws, Star Wars: Outlaws is a game I genuinely enjoyed from start to finish. Granted, many of its strengths are a result of it being a Star Wars game, but as a fan of the franchise thats enough for me.
To me, this game nailed the feeling of being a roguish scoundrel going on adventures across the Star Wars galaxy. From classic locations such as Mos Eisley, to new places like Mirogana, it all felt authentically a part of that galaxy far, far away. Its clear the people behind the game are big fans of the universe George Lucas created.
Even the typical Ubisoft open-world tropes didnt detract from the experience. In fact, setting the game across multiple planets, and therefore segmenting the game into smaller open areas instead of one huge map, did a lot to remove the tedium that comes with open-world games.
Another aspect of the game I enjoyed was the “Reputation System”. During the course of the game youll encounter and do missions for various criminal syndicates; The Hutts, The Pykes, Crimson Dawn, and the Ashiga Clan. Which missions you do, and whether you succeed or fail, will affect your standing with these organizations. Raising your reputation with a particular group can unlock special merchants, allow you to take higher paying missions, and freely move about the gangs territory. However, betraying a gang, stealing from them, entering restricted areas, or just being a menace towards them, will lower your reputation. Its a cool system, and I think it has plenty of room for iteration in a sequel.
### Final Fantasy VII Rebirth
I have to say, this is the game that most surprised me this year. While I enjoyed Final Fantasy VII Remakethe first entry in this trilogy-to-be of games re-imagining the classic 90s RPGwhen I originally played it during Covid lockdown in 2020, I found it very tedious when I revisited it a couple years ago In addition, 2023s Final Fantasy XVI left me a bit down on the series as a whole. But I gave Rebirth a shot anyway, and Im glad I did.
One thing this game shares in common with the first entry is how well it handles real-time combat, especially compared to the more recent “mainline” entries. Final Fantasy XVs real-time combat was tedious, while XVIs was frustrating and shallow. I really appreciate the ability in this game to switch characters in combat to not only keep gameplay interesting, but provide a level of depth and control that the aforementioned mainline games just dont.
The world design, similar to Star Wars: Outlaws, is more segmented, which makes the exploration much less tedious, and far more varied. Each map is littered with side objectives to encourage exploration, but its not so much that its overwhelming. The only 2 exceptions were Cosmo Canyon and Gongaga, which I found extremely convoluted and not at all enjoyable to navigate.
The game has a multitude of mini-games, which felt like a throwback to an older style of video game design, and I thought it was fun. They werent all bangers, but I did find myself engaging in Gwen…sorry, I mean, Queens Blood. Also, Chocobo Racing ended up being another big time sink. It was enough to keep me coming back for many more hours, even after I finished the story (and is probably why I didnt finish more games this year 😬).
### The Legend of Zelda: Echoes of Wisdom
It goes without saying, if theres a new Zelda game out its going to make my top 3 games of the year, no question. Like any other game, its not perfect. As the first brand-new “2D” Zelda in a decade, and the first in the series to star the titular princess, it had high expectations to live up to, but I think it ran away with them.
Its the first Zelda game of this style to take on the open-world design of the 2 most recent 3D gamesBreath of the Wild, and Tears of the Kingdomand it really fit a lot better that I was expecting. In fact, Id say it did the open-world much better, because it was reigned in just enough to not impede on the storytelling (such as it is in a Nintendo title), but still gave the player a good level of freedom to explore.
Another area this game excels is the puzzles. Much like in Tears of the Kingdom, the puzzles in this game are more focused on player creativity and finding fun solutions than simply trying to figure out the one solution the designers intended. Much of this creativity comes from what this game calls “echoes”, basically various objects and enemies you can conjure up.
I hope this is a concept Nintendo revisits, because I really want to see a successor to this game that iterates upon what is already great, and improves on what didnt quite work. Basically, what Tears of the Kingdom did for Breath of the Wild.
+3 -3
View File
@@ -20,9 +20,9 @@ _Last updated: November 21, 2024_
## 🎮 Playing
- [Horizon: Zero Dawn Remastered](https://thegamesdb.net/game.php?id=114602)
- [Paper Mario: The Thousand Year Door](https://thegamesdb.net/game.php?id=118815)
- [Fortnite](https://thegamesdb.net/game.php?id=84367)
- [Dragon Age: The Veilguard](https://www.igdb.com/games/dragon-age-the-veilguard)
- [Paper Mario: The Thousand Year Door](https://www.igdb.com/games/paper-mario-the-thousand-year-door--1)
- [Fortnite](https://www.igdb.com/games/fortnite)
## 📺 Watching