user()); return match ($verb) { 'friend' => $this->friend($request, $me), 'accept-friend' => $this->acceptFriend($request, $me), 'marry' => $this->marry($request, $me), 'child' => $this->child($request, $me), default => response()->json(['message' => __('city.social_unknown')], 422), }; } /** * Pending incoming social requests for the caller. */ public function inbox(Request $request): JsonResponse { $me = Character::ensureForUser($request->user()); $pending = Relationship::query() ->where('character_b_id', $me->id) ->where('status', Relationship::STATUS_PENDING) ->with('characterA:id,name') ->get() ->map(fn (Relationship $r) => [ 'id' => $r->id, 'type' => $r->type, 'from' => $r->characterA?->name, ]); $friends = Relationship::query() ->where('status', Relationship::STATUS_ACCEPTED) ->where('type', Relationship::TYPE_FRIEND) ->where(fn ($q) => $q->where('character_a_id', $me->id)->orWhere('character_b_id', $me->id)) ->get() ->map(function (Relationship $r) use ($me) { $otherId = (int) $r->character_a_id === (int) $me->id ? $r->character_b_id : $r->character_a_id; return Character::query()->whereKey($otherId)->first(['id', 'name']); }) ->filter(); return response()->json([ 'pending' => $pending, 'friends' => $friends, ]); } /** * Send a friendship request to another character. */ private function friend(Request $request, Character $me): JsonResponse { $data = $request->validate(['character_id' => ['required', 'integer', 'exists:characters,id']]); $other = Character::query()->findOrFail($data['character_id']); if ((int) $other->id === (int) $me->id) { return response()->json(['message' => __('city.social_self')], 422); } $existing = Relationship::query() ->where('type', Relationship::TYPE_FRIEND) ->where(fn ($q) => $q->where('character_a_id', $me->id)->where('character_b_id', $other->id)) ->orWhere(fn ($q) => $q->where('character_a_id', $other->id)->where('character_b_id', $me->id)) ->first(); if ($existing) { return response()->json(['message' => __('city.social_exists')], 422); } Relationship::create([ 'character_a_id' => $me->id, 'character_b_id' => $other->id, 'type' => Relationship::TYPE_FRIEND, 'status' => Relationship::STATUS_PENDING, ]); return response()->json(['message' => __('city.social_friend_sent')]); } /** * Accept an incoming friendship request. */ private function acceptFriend(Request $request, Character $me): JsonResponse { $data = $request->validate(['relationship_id' => ['required', 'integer', 'exists:relationships,id']]); $rel = Relationship::query()->findOrFail($data['relationship_id']); if ((int) $rel->character_b_id !== (int) $me->id || $rel->type !== Relationship::TYPE_FRIEND) { return response()->json(['message' => __('auth.forbidden')], 403); } $rel->status = Relationship::STATUS_ACCEPTED; $rel->save(); return response()->json(['message' => __('city.social_friend_ok')]); } /** * Marry an accepted friend (one spouse max). */ private function marry(Request $request, Character $me): JsonResponse { $data = $request->validate(['character_id' => ['required', 'integer', 'exists:characters,id']]); $other = Character::query()->findOrFail($data['character_id']); $friendship = Relationship::query() ->where('type', Relationship::TYPE_FRIEND) ->where('status', Relationship::STATUS_ACCEPTED) ->where(fn ($q) => $q->where('character_a_id', $me->id)->where('character_b_id', $other->id) ->orWhere(fn ($q2) => $q2->where('character_a_id', $other->id)->where('character_b_id', $me->id))) ->exists(); if (! $friendship) { return response()->json(['message' => __('city.social_need_friend')], 422); } $existingSpouse = Relationship::query() ->where('type', Relationship::TYPE_SPOUSE) ->where('status', Relationship::STATUS_ACCEPTED) ->where(fn ($q) => $q->where('character_a_id', $me->id)->orWhere('character_b_id', $me->id)) ->exists(); if ($existingSpouse) { return response()->json(['message' => __('city.social_married')], 422); } Relationship::create([ 'character_a_id' => $me->id, 'character_b_id' => $other->id, 'type' => Relationship::TYPE_SPOUSE, 'status' => Relationship::STATUS_ACCEPTED, ]); return response()->json(['message' => __('city.social_married_ok')]); } /** * Have a child with the current spouse (creates an NPC character). */ private function child(Request $request, Character $me): JsonResponse { $data = $request->validate(['character_id' => ['required', 'integer', 'exists:characters,id']]); $spouse = Character::query()->findOrFail($data['character_id']); $married = Relationship::query() ->where('type', Relationship::TYPE_SPOUSE) ->where('status', Relationship::STATUS_ACCEPTED) ->where(fn ($q) => $q->where('character_a_id', $me->id)->where('character_b_id', $spouse->id) ->orWhere(fn ($q2) => $q2->where('character_a_id', $spouse->id)->where('character_b_id', $me->id))) ->exists(); if (! $married) { return response()->json(['message' => __('city.social_need_spouse')], 422); } $childName = Str::limit($me->name.' '.$spouse->name, 40, ''); $child = Character::create([ 'user_id' => null, 'city_id' => $me->city_id, 'name' => trim($childName) ?: 'Child', 'skin' => $me->skin, 'hair' => $me->hair, 'shirt' => random_int(1, 5), 'pos_x' => $me->pos_x + 1, 'pos_z' => $me->pos_z + 1, 'money' => 0, 'energy' => 100, 'hunger' => 100, 'thirst' => 100, 'state' => Character::STATE_AWAKE, 'education' => 0, 'is_online' => false, ]); foreach ([$me, $spouse] as $parent) { Relationship::create([ 'character_a_id' => $child->id, 'character_b_id' => $parent->id, 'type' => Relationship::TYPE_PARENT_CHILD, 'status' => Relationship::STATUS_ACCEPTED, ]); } return response()->json([ 'message' => __('city.social_child_ok'), 'child' => ['id' => $child->id, 'name' => $child->name], ]); } }