Toy process fix#3389
Conversation
fix canvas frame for large canvas fix choker snap
|
Caution Review failedAn error occurred during the review process. Please try again later. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (5)
code/game/objects/structures/artstuff.dm (1)
548-556: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winВынесите оффсеты и frame-ресурс из хардкода.
Здесь зашиты магические числа (
9,4,1) и знание о двух конкретных подтипах холста. Это быстро разъедется при следующем добавлении ещё одного большого канваса или правке спрайтов. Лучше хранитьframe_icon, suffix дляicon_stateи смещения на самом/obj/item/canvas, а здесь только читать их безistype()-ветки.♻️ Вариант упрощения
/obj/item/canvas + var/frame_icon + var/frame_icon_state_suffix = "frame" + var/frame_offset_x = -1 + var/frame_offset_y = -1 /obj/item/canvas/thirtysix_twentyfour + frame_icon = 'icons/obj/art/artstuff_64x64.dmi' + frame_icon_state_suffix = "frame_simple" + frame_offset_x = -9 + frame_offset_y = -4 /obj/item/canvas/fortyfive_twentyseven + frame_icon = 'icons/obj/art/artstuff_64x64.dmi' + frame_icon_state_suffix = "frame_simple" + frame_offset_x = -9 + frame_offset_y = -4 /obj/structure/sign/painting/update_overlays() . = ..() if(!current_canvas?.generated_icon) return var/mutable_appearance/MA = mutable_appearance(current_canvas.generated_icon) MA.pixel_x = current_canvas.framed_offset_x MA.pixel_y = current_canvas.framed_offset_y . += MA - if(istype(current_canvas, /obj/item/canvas/thirtysix_twentyfour) || istype(current_canvas, /obj/item/canvas/fortyfive_twentyseven)) - var/mutable_appearance/frame = mutable_appearance('icons/obj/art/artstuff_64x64.dmi', "[current_canvas.icon_state]frame_simple") - frame.pixel_x = current_canvas.framed_offset_x - 9 - frame.pixel_y = current_canvas.framed_offset_y - 4 - . += frame - else - var/mutable_appearance/frame = mutable_appearance(current_canvas.icon,"[current_canvas.icon_state]frame") - frame.pixel_x = current_canvas.framed_offset_x - 1 - frame.pixel_y = current_canvas.framed_offset_y - 1 - . += frame + var/frame_icon = current_canvas.frame_icon || current_canvas.icon + var/mutable_appearance/frame = mutable_appearance(frame_icon, "[current_canvas.icon_state][current_canvas.frame_icon_state_suffix]") + frame.pixel_x = current_canvas.framed_offset_x + current_canvas.frame_offset_x + frame.pixel_y = current_canvas.framed_offset_y + current_canvas.frame_offset_y + . += frameAs per path instructions,
**/*.dm: "No magic numbers — use#defineconstants".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@code/game/objects/structures/artstuff.dm` around lines 548 - 556, The framing logic in the canvas appearance code is hardcoded with magic offsets and a special-case type check, making it brittle for new canvas variants. Move the frame icon resource, icon_state suffix, and pixel offsets onto /obj/item/canvas (or shared vars used by current_canvas) and have this branch read those values directly instead of using istype() for specific subtypes. Replace the literal 9, 4, and 1 adjustments with named constants or per-canvas properties, and keep the mutable_appearance setup in the existing canvas/frame rendering path.Source: Path instructions
code/controllers/subsystem/processing/obj.dm (1)
8-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winВынесите интервал
SSobjlwв именованную константу и time define.
wait = 2скрывает, что тут используются децисекунды, и это легко перепутать с секундами при настройкеdelta_time-логики. Лучше оформить это как#defineсSECONDS, например0.2 SECONDS. As per path instructions, useTime defines (SECONDS, MINUTES, HOURS) not raw decisecondsandNo magic numbers — use#defineconstants.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@code/controllers/subsystem/processing/obj.dm` around lines 8 - 12, The ObjectsLewd subsystem definition uses a raw decisecond value in PROCESSING_SUBSYSTEM_DEF(objlw), which should be replaced with a named constant and time define. Update the wait setting to use a `#define` for the interval and express it with SECONDS (for example, 0.2 SECONDS) so the timing intent is explicit and not mistaken for seconds. Keep the change localized to the objlw subsystem definition and the new constant declaration.Source: Path instructions
modular_bluemoon/code/modules/arousal/toys/dildos.dm (1)
159-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winНе оставляйте интервал процесса сырыми децисекундами.
rand(50,350)лучше заменить на именованные#define-границы черезSECONDS, чтобы единицы и баланс были явными.♻️ Возможная правка
+#define DILDO_PROCESS_MIN_INTERVAL (5 SECONDS) +#define DILDO_PROCESS_MAX_INTERVAL (35 SECONDS) + /obj/item/dildo/process(delta_time) if(timer > 0) // chech interval timer -= delta_time return else - timer = rand(50,350) + timer = rand(DILDO_PROCESS_MIN_INTERVAL, DILDO_PROCESS_MAX_INTERVAL)As per path instructions, "No magic numbers — use
#defineconstants" and "Time defines (SECONDS, MINUTES, HOURS) not raw deciseconds".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modular_bluemoon/code/modules/arousal/toys/dildos.dm` around lines 159 - 163, The timer reset in the dildo arousal logic uses raw decisecond values, which should be replaced with named time constants. Update the timer assignment in the relevant toy cooldown logic so the interval is defined through existing or new `#define` constants using SECONDS, rather than rand(50,350), and keep the timer handling in the same function/block so the balance and units are explicit.Source: Path instructions
modular_bluemoon/code/modules/arousal/toys/tentacle_panties.dm (1)
90-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winВынесите интервалы в named time constants.
rand(120,300),rand(5,10),rand(2,5),rand(0.8,2)иrand(0.2,0.5)сейчас выглядят как магические числа. Для processing-таймеров лучше использовать#defineс понятными именами иSECONDS.As per path instructions, "No magic numbers — use
#defineconstants" and "Time defines (SECONDS, MINUTES, HOURS) not raw deciseconds".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modular_bluemoon/code/modules/arousal/toys/tentacle_panties.dm` around lines 90 - 140, The timer interval values in the tentacle_panties processing logic are hardcoded magic numbers; replace the raw rand() ranges in the tired reset and lust-based timer branches with named time constants using `#define` and SECONDS. Update the timing logic in the routine that manages timer, tired, and lust so the intervals are self-documenting and consistent with the project’s time-define conventions.Source: Path instructions
modular_bluemoon/code/modules/arousal/toys/buttplug.dm (1)
137-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winЗамените сырой интервал на именованные time-константы.
rand(50,350)скрывает единицы измерения и нарушает локальный DM-style для таймеров. Лучше вынести границы в#defineи записать как5 SECONDS/35 SECONDS.♻️ Возможная правка
+#define BUTTPLUG_PROCESS_MIN_INTERVAL (5 SECONDS) +#define BUTTPLUG_PROCESS_MAX_INTERVAL (35 SECONDS) + /obj/item/buttplug/process(delta_time) if(timer > 0) // chech interval timer -= delta_time return else - timer = rand(50,350) + timer = rand(BUTTPLUG_PROCESS_MIN_INTERVAL, BUTTPLUG_PROCESS_MAX_INTERVAL)else to_chat(user, span_love(pick("Я чувствую анальную затычку внутри!", "Вы чувствуете удовольствие от затычки глубоко внутри!"))) user.handle_post_sex(LOW_LUST*2, null, user) user.plug13_genital_emote(loc, LOW_LUST*2 * 2) + +#undef BUTTPLUG_PROCESS_MIN_INTERVAL +#undef BUTTPLUG_PROCESS_MAX_INTERVALAs per path instructions, "No magic numbers — use
#defineconstants" and "Time defines (SECONDS, MINUTES, HOURS) not raw deciseconds".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modular_bluemoon/code/modules/arousal/toys/buttplug.dm` around lines 137 - 141, The timer reset in the bu ttplug arousal module uses raw numeric bounds in the `rand(...)` call, which should be replaced with named time constants. Update the timer logic in `buttplug.dm` to use `#define`d min/max interval constants and express them with DM time defines like `5 SECONDS` and `35 SECONDS` so the intent and units are explicit. Keep the `timer`/`delta_time` flow unchanged, and adjust the `rand(...)` assignment in the same block to reference those constants instead of magic numbers.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@modular_bluemoon/code/modules/arousal/structure/dildo_machine.dm`:
- Around line 26-28: The Destroy override is too broad because it targets
/obj/structure/bed instead of only the dildo machine. Update the Destroy()
definition in the dildo_machine hierarchy to
/obj/structure/bed/dildo_machine/Destroy() so STOP_PROCESSING(SSobjlw, src) only
runs for that specific object and does not affect all beds. Keep the existing
cleanup flow with the parent call intact.
- Around line 129-142: The timing logic in dildo_machine.process currently
triggers fuck() immediately on the first tick and adds an extra subsystem tick
to every interval because timer is checked before being decremented. Update the
timer handling in the dildo_machine activation/process flow so timer is
initialized when turning on, then in process(delta_time) subtract delta_time
first and only call fuck() once the timer reaches zero or below, resetting it
from speed_delay[mode] after the action. Keep the fix localized to the existing
timer, on state, and process() logic.
In `@modular_bluemoon/code/modules/arousal/structure/sybian.dm`:
- Around line 43-56: The timing logic in sybian.process is causing the first
vibration to fire immediately and then stretching the interval because timer
starts at 0 and is checked before being decremented. Update the start/stop flow
in the on block and process(delta_time) so timer is reset to interval when
activation begins and the countdown subtracts delta_time before deciding whether
to vibrate. Keep the fix localized to /obj/structure/chair/sybian and its
timer/interval handling so re-enabling does not reuse stale timer state.
In `@modular_bluemoon/code/modules/arousal/toys/magic_wand.dm`:
- Around line 192-211: The shared post-use effects in magic_wand.dm are
incorrectly nested under M.has_vagina(), so characters with only a penis miss
handle_post_sex, plug13 emote, jitter, and sound in modes 1 and 2. Move the
common effect block out of the M.has_vagina() branch inside the relevant magic
wand handling logic so it runs for any applicable target, while keeping the
sex-specific chat messages gated by has_penis() and has_vagina().
- Around line 161-165: The `Mob` value is only a `/mob/living/carbon` hint, so
`w_underwear` access in the `magic_wand.dm` check can still hit a non-human at
runtime. In the relevant proc, cast `Mob` to `/mob/living/carbon/human` with
`astype()` before using `M.w_underwear`, and keep the early exit path in place
when the cast fails or the type check does not pass.
- Around line 167-170: The on/off flow in magic_wand.dm leaves no way to resume
processing after `process()` stops it for an unequipped-off item. Update the
toggle path in `attack_self()` and the shutdown logic in `process()` so that
when the wand is turned back on while still worn (`w_underwear`), it calls
`START_PROCESSING(SSobj, src)` again and resumes periodic vibration; keep
`STOP_PROCESSING(SSobj, src)` only for the off state and ensure `Mob` is handled
consistently when restarting.
In `@modular_bluemoon/code/modules/arousal/toys/tentacle_panties.dm`:
- Around line 11-13: The tentacle underwear uses different processing subsystems
for registration and cleanup, which can leave a stale entry behind. Make
`equipped()` and the unequip path use the same subsystem as `Destroy()` and the
`STOP_PROCESSING` calls, and ensure
`/obj/item/clothing/underwear/briefs/tentacle/Destroy()` also clears `Mob`
before calling the parent cleanup. Update the related tentacle underwear
handlers so all processing lifecycle paths consistently target the same
subsystem.
- Around line 83-86: The `M = Mob` cast in the `tentacle_panties` logic is only
a compile-time hint, so it can still leave `M` wrong-typed before `w_underwear`
is accessed. Update the guard in this block to use an `astype()` runtime check
before touching `M.w_underwear`, and keep the `STOP_PROCESSING(SSobjlw, src)`
path for non-human values. Locate the fix around the `Mob` to `human` cast in
the tentacle panties process code.
In `@modular_bluemoon/code/modules/mob/living/living.dm`:
- Around line 37-43: The `snaped` check in `living.dm` is comparing the item
instance `C` from `get_item_by_slot()` against a list of type paths, so `C in
snaped` is always false and the snap branch never runs. Update the condition in
this item-handling block to compare `C` by type/path instead of object
membership, using the existing `snaped` data from `facefuck.dm` and the
surrounding `take_damage()`, `dropItemToGround()`, and `visible_message()`
logic.
In
`@modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm`:
- Around line 172-183: Unify the duplicated `BiologicalLife(delta_time,
times_fired)` logic for `/mob/living/simple_animal/hostile/tentacles` into a
single override so the regen/tired handling and the timer-based
`do_lewd_action()` flow live together in one place. Keep the existing behavior
from both versions inside that one method, and add a null check around `target`
before assigning to `M` or reading `M.pulledby` to avoid runtime errors when no
target is set.
- Around line 180-183: Guard the target before dereferencing it in the tentacles
logic: the current check in the mob routine that assigns target to M and then
reads M.pulledby can runtime when target is null. Update the early flow in the
same tentacles behavior so it returns immediately if M is null, if M.pulledby is
absent, or if tired is true, before calling do_lewd_action.
In `@modular_splurt/code/game/objects/items/lewd_items/vibrator.dm`:
- Around line 126-140: In attack_self() on vibrator.dm, changing mode only
updates the vibration strength but leaves the currently running soundloop on the
old setting until remote-toggle runs. Update the mode-switch logic so the active
soundloop is refreshed immediately whenever the mode changes, using the existing
vibrator/state helpers around attack_self(), startVibing(), and stopVibing() to
keep sound and effects in sync.
---
Nitpick comments:
In `@code/controllers/subsystem/processing/obj.dm`:
- Around line 8-12: The ObjectsLewd subsystem definition uses a raw decisecond
value in PROCESSING_SUBSYSTEM_DEF(objlw), which should be replaced with a named
constant and time define. Update the wait setting to use a `#define` for the
interval and express it with SECONDS (for example, 0.2 SECONDS) so the timing
intent is explicit and not mistaken for seconds. Keep the change localized to
the objlw subsystem definition and the new constant declaration.
In `@code/game/objects/structures/artstuff.dm`:
- Around line 548-556: The framing logic in the canvas appearance code is
hardcoded with magic offsets and a special-case type check, making it brittle
for new canvas variants. Move the frame icon resource, icon_state suffix, and
pixel offsets onto /obj/item/canvas (or shared vars used by current_canvas) and
have this branch read those values directly instead of using istype() for
specific subtypes. Replace the literal 9, 4, and 1 adjustments with named
constants or per-canvas properties, and keep the mutable_appearance setup in the
existing canvas/frame rendering path.
In `@modular_bluemoon/code/modules/arousal/toys/buttplug.dm`:
- Around line 137-141: The timer reset in the bu
ttplug arousal module uses raw numeric bounds in the `rand(...)` call, which
should be replaced with named time constants. Update the timer logic in
`buttplug.dm` to use `#define`d min/max interval constants and express them with
DM time defines like `5 SECONDS` and `35 SECONDS` so the intent and units are
explicit. Keep the `timer`/`delta_time` flow unchanged, and adjust the
`rand(...)` assignment in the same block to reference those constants instead of
magic numbers.
In `@modular_bluemoon/code/modules/arousal/toys/dildos.dm`:
- Around line 159-163: The timer reset in the dildo arousal logic uses raw
decisecond values, which should be replaced with named time constants. Update
the timer assignment in the relevant toy cooldown logic so the interval is
defined through existing or new `#define` constants using SECONDS, rather than
rand(50,350), and keep the timer handling in the same function/block so the
balance and units are explicit.
In `@modular_bluemoon/code/modules/arousal/toys/tentacle_panties.dm`:
- Around line 90-140: The timer interval values in the tentacle_panties
processing logic are hardcoded magic numbers; replace the raw rand() ranges in
the tired reset and lust-based timer branches with named time constants using
`#define` and SECONDS. Update the timing logic in the routine that manages timer,
tired, and lust so the intervals are self-documenting and consistent with the
project’s time-define conventions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3173a1b8-c8c5-4c9d-af30-ae3c50498595
📒 Files selected for processing (12)
code/controllers/subsystem/processing/obj.dmcode/game/objects/structures/artstuff.dmmodular_bluemoon/code/modules/arousal/structure/dildo_machine.dmmodular_bluemoon/code/modules/arousal/structure/sybian.dmmodular_bluemoon/code/modules/arousal/toys/buttplug.dmmodular_bluemoon/code/modules/arousal/toys/dildos.dmmodular_bluemoon/code/modules/arousal/toys/magic_wand.dmmodular_bluemoon/code/modules/arousal/toys/tentacle_panties.dmmodular_bluemoon/code/modules/mob/living/living.dmmodular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dmmodular_sand/code/datums/interactions/interaction_datums/lewd/facefuck.dmmodular_splurt/code/game/objects/items/lewd_items/vibrator.dm
| /obj/structure/bed/Destroy() | ||
| STOP_PROCESSING(SSobjlw,src) | ||
| . = ..() |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Destroy() сейчас переопределяет все кровати, а не только dildo_machine.
На Line 26 объявлен /obj/structure/bed/Destroy(), поэтому STOP_PROCESSING(SSobjlw, src) начнёт выполняться для любого /obj/structure/bed. Это слишком широкий хук; вдобавок STOP_PROCESSING снимает общий DF_ISPROCESSING флаг, так что вы трогаете состояние объектов вне этой машины. Здесь нужен /obj/structure/bed/dildo_machine/Destroy().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/structure/dildo_machine.dm` around
lines 26 - 28, The Destroy override is too broad because it targets
/obj/structure/bed instead of only the dildo machine. Update the Destroy()
definition in the dildo_machine hierarchy to
/obj/structure/bed/dildo_machine/Destroy() so STOP_PROCESSING(SSobjlw, src) only
runs for that specific object and does not affect all beds. Keep the existing
cleanup flow with the parent call intact.
| START_PROCESSING(SSobjlw,src) | ||
| if(!on) | ||
| STOP_PROCESSING(SSobjlw,src) | ||
| if(user) | ||
| to_chat(user, span_notice("[src] в[on ? "" : "ы"]ключена.")) | ||
|
|
||
| /obj/structure/bed/dildo_machine/process(delta_time) | ||
| if(timer > 0) // chech interval | ||
| timer -= delta_time | ||
| return | ||
| else | ||
| timer = speed_delay[mode] | ||
|
|
||
| fuck() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Таймер сейчас даёт лишний тик задержки и первый толчок сразу после включения.
С timer = 0 первый process() сразу вызывает fuck(), а проверка if(timer > 0) до вычитания delta_time растягивает каждый следующий интервал ещё на один тик подсистемы. На high это фактически удваивает паузу между вызовами. Инициализируйте timer при включении и сначала уменьшайте его на delta_time, а уже потом проверяйте порог.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/structure/dildo_machine.dm` around
lines 129 - 142, The timing logic in dildo_machine.process currently triggers
fuck() immediately on the first tick and adds an extra subsystem tick to every
interval because timer is checked before being decremented. Update the timer
handling in the dildo_machine activation/process flow so timer is initialized
when turning on, then in process(delta_time) subtract delta_time first and only
call fuck() once the timer reaches zero or below, resetting it from
speed_delay[mode] after the action. Keep the fix localized to the existing
timer, on state, and process() logic.
| if(on) | ||
| START_PROCESSING(SSobjlw,src) | ||
| to_chat(usr, "[src] вкл.") | ||
| else | ||
| STOP_PROCESSING(SSobjlw,src) | ||
| to_chat(usr, "[src] выкл.") | ||
|
|
||
| /obj/structure/chair/sybian/process(delta_time) | ||
| if(timer > 0) // chech interval | ||
| timer -= delta_time | ||
| return | ||
| else | ||
| timer = interval | ||
| vibrate() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Тут тот же сдвиг таймера: первый импульс мгновенный, дальше интервал длиннее заданного.
timer стартует с 0, поэтому после включения vibrate() срабатывает в первый же process(). Затем из-за проверки до timer -= delta_time цикл получает лишний тик ожидания на каждом проходе и ещё может переиспользовать старый timer после повторного включения. Сбрасывайте timer = interval при старте и сначала уменьшайте его на delta_time.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/structure/sybian.dm` around lines 43 -
56, The timing logic in sybian.process is causing the first vibration to fire
immediately and then stretching the interval because timer starts at 0 and is
checked before being decremented. Update the start/stop flow in the on block and
process(delta_time) so timer is reset to interval when activation begins and the
countdown subtracts delta_time before deciding whether to vibrate. Keep the fix
localized to /obj/structure/chair/sybian and its timer/interval handling so
re-enabling does not reuse stale timer state.
| var/mob/living/carbon/human/M = Mob | ||
| if(!istype(src, M.w_underwear)) | ||
| STOP_PROCESSING(SSobj,src) | ||
| Mob = null | ||
| return |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Скастуйте Mob перед доступом к human-only полям.
Mob хранится как /mob/living/carbon, но w_underwear есть не у любого carbon-типа. Используйте astype() и ранний выход перед обращением к M.w_underwear.
🛡️ Возможная правка
- var/mob/living/carbon/human/M = Mob
- if(!istype(src, M.w_underwear))
+ var/mob/living/carbon/human/M = astype(Mob, /mob/living/carbon/human)
+ if(!M || !istype(src, M.w_underwear))
STOP_PROCESSING(SSobj,src)
Mob = null
returnBased on learnings, DM proc/type annotations are compile-time hints only and are not enforced at runtime. As per path instructions, BYOND 516 code should prefer astype(val, /type).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var/mob/living/carbon/human/M = Mob | |
| if(!istype(src, M.w_underwear)) | |
| STOP_PROCESSING(SSobj,src) | |
| Mob = null | |
| return | |
| var/mob/living/carbon/human/M = astype(Mob, /mob/living/carbon/human) | |
| if(!M || !istype(src, M.w_underwear)) | |
| STOP_PROCESSING(SSobj,src) | |
| Mob = null | |
| return |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/toys/magic_wand.dm` around lines 161 -
165, The `Mob` value is only a `/mob/living/carbon` hint, so `w_underwear`
access in the `magic_wand.dm` check can still hit a non-human at runtime. In the
relevant proc, cast `Mob` to `/mob/living/carbon/human` with `astype()` before
using `M.w_underwear`, and keep the early exit path in place when the cast fails
or the type check does not pass.
Sources: Path instructions, Learnings
| if(!on) | ||
| STOP_PROCESSING(SSobj,src) | ||
| Mob = null | ||
| return |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Не останавливайте processing без пути повторного запуска.
Если предмет надет выключенным, первый process() очищает Mob и снимает объект с SSobj; последующее включение через attack_self() не вызывает START_PROCESSING, поэтому периодическая вибрация уже не запустится до переэкипировки.
🐛 Возможная правка
if(!on)
- STOP_PROCESSING(SSobj,src)
- Mob = null
returnЛибо добавьте в attack_self() запуск processing при включении, если src всё ещё находится в w_underwear.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if(!on) | |
| STOP_PROCESSING(SSobj,src) | |
| Mob = null | |
| return | |
| if(!on) | |
| return |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/toys/magic_wand.dm` around lines 167 -
170, The on/off flow in magic_wand.dm leaves no way to resume processing after
`process()` stops it for an unequipped-off item. Update the toggle path in
`attack_self()` and the shutdown logic in `process()` so that when the wand is
turned back on while still worn (`w_underwear`), it calls
`START_PROCESSING(SSobj, src)` again and resumes periodic vibration; keep
`STOP_PROCESSING(SSobj, src)` only for the off state and ensure `Mob` is handled
consistently when restarting.
| var/mob/living/carbon/human/M = Mob | ||
|
|
||
| if(!istype(src, M.w_underwear)) | ||
| STOP_PROCESSING(SSobjlw,src) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Проверьте human-cast перед w_underwear.
Mob объявлен как /mob/living/carbon, поэтому прямое присваивание в human-typed переменную не защищает от wrong-typed значения в DM. Перед доступом к w_underwear нужен astype() guard.
🛡️ Возможная правка
- var/mob/living/carbon/human/M = Mob
+ var/mob/living/carbon/human/M = astype(Mob, /mob/living/carbon/human)
- if(!istype(src, M.w_underwear))
+ if(!M || !istype(src, M.w_underwear))
STOP_PROCESSING(SSobjlw,src)
Mob = null
returnBased on learnings, DM proc/type annotations are compile-time hints only and are not enforced at runtime. As per path instructions, BYOND 516 code should prefer astype(val, /type).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var/mob/living/carbon/human/M = Mob | |
| if(!istype(src, M.w_underwear)) | |
| STOP_PROCESSING(SSobjlw,src) | |
| var/mob/living/carbon/human/M = astype(Mob, /mob/living/carbon/human) | |
| if(!M || !istype(src, M.w_underwear)) | |
| STOP_PROCESSING(SSobjlw,src) | |
| Mob = null | |
| return |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/arousal/toys/tentacle_panties.dm` around lines
83 - 86, The `M = Mob` cast in the `tentacle_panties` logic is only a
compile-time hint, so it can still leave `M` wrong-typed before `w_underwear` is
accessed. Update the guard in this block to use an `astype()` runtime check
before touching `M.w_underwear`, and keep the `STOP_PROCESSING(SSobjlw, src)`
path for non-human values. Locate the fix around the `Mob` to `human` cast in
the tentacle panties process code.
Sources: Path instructions, Learnings
| if(C in snaped) | ||
| if(prob(15)) | ||
| C.take_damage(80,BRUTE) | ||
| M.dropItemToGround(C) | ||
| playsound(src, 'modular_bluemoon/sound/effects/snap.ogg', 30, 1, -1) | ||
| visible_message(span_danger("[C] snaps!")) | ||
| return TRUE |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Проверка snaped сейчас делает ветку недостижимой.
C здесь — экземпляр предмета из get_item_by_slot(), а snaped в facefuck.dm хранит type paths. Условие C in snaped поэтому всегда ложно, и take_damage(), dropItemToGround() и сам “snap” для этих ошейников больше не сработают. Нужна проверка по типу, а не membership по объекту.
Возможная правка
- if(C in snaped)
+ if(is_type_in_list(C, snaped))
if(prob(15))
C.take_damage(80,BRUTE)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if(C in snaped) | |
| if(prob(15)) | |
| C.take_damage(80,BRUTE) | |
| M.dropItemToGround(C) | |
| playsound(src, 'modular_bluemoon/sound/effects/snap.ogg', 30, 1, -1) | |
| visible_message(span_danger("[C] snaps!")) | |
| return TRUE | |
| if(is_type_in_list(C, snaped)) | |
| if(prob(15)) | |
| C.take_damage(80,BRUTE) | |
| M.dropItemToGround(C) | |
| playsound(src, 'modular_bluemoon/sound/effects/snap.ogg', 30, 1, -1) | |
| visible_message(span_danger("[C] snaps!")) | |
| return TRUE |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_bluemoon/code/modules/mob/living/living.dm` around lines 37 - 43, The
`snaped` check in `living.dm` is comparing the item instance `C` from
`get_item_by_slot()` against a list of type paths, so `C in snaped` is always
false and the snap branch never runs. Update the condition in this item-handling
block to compare `C` by type/path instead of object membership, using the
existing `snaped` data from `facefuck.dm` and the surrounding `take_damage()`,
`dropItemToGround()`, and `visible_message()` logic.
| /mob/living/simple_animal/hostile/tentacles/BiologicalLife(delta_time, times_fired) | ||
| . = ..() | ||
| if(timer > 0) // chech interval | ||
| timer -= delta_time | ||
| return | ||
| else | ||
| timer = rand(5,20) | ||
|
|
||
| var/mob/living/M = target | ||
|
|
||
| if(M.pulledby && !tired) | ||
| do_lewd_action(M) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the file and inspect the relevant proc definitions.
git ls-files modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm
wc -l modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm
printf '\n--- first BiologicalLife definition ---\n'
sed -n '80,120p' modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm
printf '\n--- second BiologicalLife definition ---\n'
sed -n '160,210p' modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm
printf '\n--- search for BiologicalLife occurrences ---\n'
rg -n "BiologicalLife" modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dmRepository: BlueMoon-Labs/BlueMoon-Station
Length of output: 2952
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the parent proc chain and any target usage to judge whether the concern is real.
rg -n "proc/BiologicalLife|BiologicalLife\(" modular_bluemoon/code/modules/mob/living/simple_animal -g '*.dm'
printf '\n--- tentacles file target usages ---\n'
rg -n "\btarget\b" modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dmRepository: BlueMoon-Labs/BlueMoon-Station
Length of output: 753
Свести BiologicalLife() в одно место.
Сейчас у /mob/living/simple_animal/hostile/tentacles два BiologicalLife(delta_time, times_fired): первая версия держит реген и спад tired, а вторая добавляет таймер и do_lewd_action(). Это нужно объединить в один override, иначе логика тентаклей распадается на две несвязанные ветки.
target здесь тоже читается без null-guard, так что M.pulledby может давать runtime на тике без цели.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm`
around lines 172 - 183, Unify the duplicated `BiologicalLife(delta_time,
times_fired)` logic for `/mob/living/simple_animal/hostile/tentacles` into a
single override so the regen/tired handling and the timer-based
`do_lewd_action()` flow live together in one place. Keep the existing behavior
from both versions inside that one method, and add a null check around `target`
before assigning to `M` or reading `M.pulledby` to avoid runtime errors when no
target is set.
| var/mob/living/M = target | ||
|
|
||
| if(M.pulledby && !tired) | ||
| do_lewd_action(M) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the target file around the cited lines and the BiologicalLife() implementation.
file="modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm"
wc -l "$file"
sed -n '140,230p' "$file"
printf '\n--- search for BiologicalLife / target assignments ---\n'
rg -n "BiologicalLife|var/mob/living/M = target|target =" "$file"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 2712
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm"
printf '--- declarations and target writes ---\n'
rg -n "var/mob/living/target|target =|target\\b" "$file"
printf '\n--- surrounding class definitions ---\n'
sed -n '1,120p' "$file"
printf '\n--- surrounding BiologicalLife override ---\n'
sed -n '160,190p' "$file"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 259
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm"
echo '--- file start ---'
sed -n '1,130p' "$file"
echo
echo '--- BiologicalLife around cited lines ---'
sed -n '160,190p' "$file"
echo
echo '--- target references in file ---'
rg -n "target|BiologicalLife" "$file"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 6375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the base BiologicalLife implementation and any call sites/expectations around target lifetime.
rg -n "/BiologicalLife\\(|proc/BiologicalLife\\(|BiologicalLife\\(delta_time" .
# Also inspect the simple_animal hierarchy for target handling.
rg -n "var/.*target|LoseTarget\\(|CanAttack\\(" modular_bluemoon code modules . -g '*.dm'Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 50387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Narrow search to likely base mob/simple_animal files if present.
fd -a "simple_animal*.dm" .
fd -a "*living*.dm" .
# Look for the parent BiologicalLife definition and related target lifecycle methods.
rg -n "/mob/.*/BiologicalLife|BiologicalLife\\(delta_time, times_fired\\)|LoseTarget\\(" .Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 767
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the parent implementation and target lifecycle in the simple_animal hierarchy.
rg -n "/mob/living/simple_animal/.*/BiologicalLife|/mob/living/simple_animal/BiologicalLife|LoseTarget\\(|target = null|var/mob/living/target" modular_bluemoon code -g '*.dm'Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 35079
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the hostile parent BiologicalLife and the two tentacles overrides.
sed -n '90,130p' code/modules/mob/living/simple_animal/hostile/hostile.dm
echo
sed -n '80,115p' modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm
echo
sed -n '168,188p' modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dmRepository: BlueMoon-Labs/BlueMoon-Station
Length of output: 3308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect target lifecycle in the hostile base.
sed -n '430,455p' code/modules/mob/living/simple_animal/hostile/hostile.dm
echo
sed -n '70,110p' code/modules/mob/living/simple_animal/hostile/hostile.dmRepository: BlueMoon-Labs/BlueMoon-Station
Length of output: 2062
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether the tentacles file has duplicate BiologicalLife definitions and how the earlier one differs.
rg -n "^/mob/living/simple_animal/hostile/tentacles/BiologicalLife|^/mob/living/simple_animal/hostile/tentacles/" modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dmRepository: BlueMoon-Labs/BlueMoon-Station
Length of output: 1280
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the base simple_animal BiologicalLife implementation and timer cadence.
sed -n '1,220p' code/modules/mob/living/simple_animal/simple_animal.dm | rg -n "BiologicalLife|timer|life"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 168
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="code/modules/mob/living/simple_animal/simple_animal.dm"
wc -l "$file"
rg -n "/mob/living/simple_animal/BiologicalLife|BiologicalLife\\(" "$file"
sed -n '1,220p' "$file" | sed -n '1,220p'Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 227
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="code/modules/mob/living/simple_animal/simple_animal.dm"
wc -l "$file"
rg -n "/mob/living/simple_animal/BiologicalLife|BiologicalLife\\(" "$file"
sed -n '1,220p' "$file"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 227
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm"
# Show the full second BiologicalLife block with a bit more context.
sed -n '168,190p' "$file"
# Show nearby target-setting / target-clearing logic in the same file.
rg -n "target =|LoseTarget\\(|CanAttack\\(|MoveToTarget\\(|BiologicalLife\\(" "$file"Repository: BlueMoon-Labs/BlueMoon-Station
Length of output: 1039
Нужен guard перед M.pulledby.
target здесь может быть null, и тогда этот тик начнёт спамить runtime при каждом срабатывании таймера. Достаточно раннего if(!M || !M.pulledby || tired) return.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@modular_bluemoon/code/modules/mob/living/simple_animal/tentacles/tentacles.dm`
around lines 180 - 183, Guard the target before dereferencing it in the
tentacles logic: the current check in the mob routine that assigns target to M
and then reads M.pulledby can runtime when target is null. Update the early flow
in the same tentacles behavior so it returns immediately if M is null, if
M.pulledby is absent, or if tired is true, before calling do_lewd_action.
Source: Learnings
| if(VIB_OFF) | ||
| mode = VIB_LOW | ||
| to_chat(user, span_notice("You twist the bottom of [src], setting it to the low setting.")) | ||
| return | ||
| if(VIB_LOW) | ||
| mode = VIB_MEDIUM | ||
| to_chat(user, span_notice("You twist the bottom of [src], setting it to the medium setting.")) | ||
| return | ||
| if(2) | ||
| mode = 3 | ||
| if(VIB_MEDIUM) | ||
| mode = VIB_HIGH | ||
| to_chat(user, span_warning("You twist the bottom of [src], setting it to the high setting.")) | ||
| return | ||
| if(3) | ||
| mode = 1 | ||
| to_chat(user, span_notice("You twist the bottom of [src], setting it to the low setting.")) | ||
| if(VIB_HIGH) | ||
| mode = VIB_OFF | ||
| stopVibing() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Обновляйте активный soundloop при смене режима.
Если постоянная вибрация уже запущена, attack_self() меняет mode, но текущий soundloop остаётся прежним до следующего remote-toggle. Эффекты будут считаться по новому режиму, а звук — по старому.
🐛 Возможная правка
if(isliving(user))
playsound(user, 'sound/effects/clock_tick.ogg', 50, 1, -1)
+ var/was_processing = datum_flags & DF_ISPROCESSING
switch(mode)
if(VIB_OFF)
mode = VIB_LOW
to_chat(user, span_notice("You twist the bottom of [src], setting it to the low setting."))
- return
if(VIB_LOW)
mode = VIB_MEDIUM
to_chat(user, span_notice("You twist the bottom of [src], setting it to the medium setting."))
- return
if(VIB_MEDIUM)
mode = VIB_HIGH
to_chat(user, span_warning("You twist the bottom of [src], setting it to the high setting."))
- return
if(VIB_HIGH)
mode = VIB_OFF
stopVibing()
to_chat(user, span_notice("You twist the bottom of [src], setting it to the off."))
return
+ if(was_processing)
+ startVibing()
+ returnAlso applies to: 249-268
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modular_splurt/code/game/objects/items/lewd_items/vibrator.dm` around lines
126 - 140, In attack_self() on vibrator.dm, changing mode only updates the
vibration strength but leaves the currently running soundloop on the old setting
until remote-toggle runs. Update the mode-switch logic so the active soundloop
is refreshed immediately whenever the mode changes, using the existing
vibrator/state helpers around attack_self(), startVibing(), and stopVibing() to
keep sound and effects in sync.
Описание
Много фиксов ЕРП стафа
Игрушки использующие костыльный цикл, перенесены в process().
Логика моба, перенесена в его BiologicalLife().
Исправлено(надеюсь, не тестировано) разрыв чокера при оральных утехах.
Добавлены рамки большим холстам.
Причина изменений
Пожалуйста, если вы не знаете как, что то сделать, смотрите как подобное уже сделано в другом месте.
Конструкция:
Еще и в главном цикле игры, это просто смерть производительности.
Для бесконечных лупов, у объектов есть
process(), у мобов естьBiologicalLife(), которые имеют какое то подобие асинхронности и приоритетов вызовов.Changelog
🆑
refactor: refactor vibrators loop code
refactor: refactor dildo loop code
refactor: refactor sybian loop code
refactor: refactor buttplug loop code
refactor: refactor tentacle attack code
refactor: refactor magicwand loop code
refactor: refactor dildomachine loop code
refactor: refactor tentaclepanties loop code
code: added SSobjlw (more faster subsystem for some lewd toys)
fix: fixed large canvas frames
fix: fixed choker snap
/:cl:
Summary by CodeRabbit
Новые функции
Исправления