Compare commits

..

6 commits

Author SHA1 Message Date
28a4346e8d Update randomizer maps 2025-01-22 23:27:27 -06:00
902ea46566 Add missing models 2025-01-22 23:25:37 -06:00
eae0356c03 Cleanup 2025-01-22 23:25:20 -06:00
e343fc0346 Add custom property support 2025-01-22 23:24:58 -06:00
6a15c9c196 Bug fixes 2025-01-21 19:46:08 -06:00
c51aa6533c Rewrite/cleanup code, split selection from spawning 2025-01-21 16:36:17 -06:00
24 changed files with 6618 additions and 1018 deletions

View file

@ -0,0 +1,28 @@
Barriers
models/props_fortifications/barricade001_128_reference.mdl Metal Mesh Barricade (128u)
models/props_fortifications/barricade001_64_reference.mdl Metal Mesh Barricade (64u)
models/props_fortifications/barricade_gate001_64_reference.mdl Metal Mesh Barricade Gate (64u)
models/props_fortifications/barricade_razorwire001_128_reference.mdl Barricade Razorwire (128u) (no collision)
models/props_fortifications/concrete_barrier01.mdl Concrete wall
models/props_fortifications/concrete_barrier001_96_reference.mdl Concrete crash barrier (96u)
models/props_fortifications/concrete_barrier001_128_reference.mdl Concrete crash barrier (128u)
models/props_fortifications/concrete_post001_48.mdl Concrete Post (48u)
models/props_fortifications/concrete_wall001_96_reference.mdl Concrete wall (96u)
models/props_fortifications/concrete_block001_128_reference.mdl Concrete block (128u)
models/props_fortifications/police_barrier001_128_reference.mdl Police Barrier Notice
models/props_fortifications/fortification_indoor_01.mdl Luggage Push Fort
models/props_fortifications/sandbags_line2.mdl Building sandbags 6 layers
models/props_fortifications/sandbags_corner3.mdl Building sandbags 4 layers curved
models/props_fortifications/sandbags_corner2.mdl Building sandbags 6 layers curved
models/props_fortifications/traffic_barrier001.mdl Traffic Barrier
models/props_urban/railroad_gate001.mdl Railroad Crossing Light
models/props_urban/railroad_gate_arm001.mdl Railroad Crossing Arm
models/props_downtown/bollards_ornate.mdl Ornate metal bollard
models/props_street/bollards_512.mdl Bollard (512u)
models/props_unique/wooden_barricade.mdl Wooden barricade (no damage)
models/props_unique/wooden_barricade_break1.mdl wooden barricade (low damage)
models/props_unique/wooden_barricade_break2.mdl Wooden barricade (medium damage)
models/props_unique/wooden_barricade_break3.mdl wooden barricade (high damage)
models/props_c17/concrete_barrier001a.mdl Concrete crash barrier-higher
models/props_exteriors/guardrail128a.mdl road guardrail (128u)
models/props_buildables/wall_barricade_helper.mdl Wall Barricade Helper

View file

@ -0,0 +1,79 @@
Fences & Gates
models/lighthouse/props/wooden_gate.mdl Valerie's fancy wooden gate
models/props_exteriors/fence002.mdl wooden fence (very long)
models/props_exteriors/fence002_end.mdl wooden fence end
models/props_urban/fence_gate001_256.mdl urban fence gate (easy to use)
models/props_urban/fence_cover001_64.mdl shelter Fence (64u)
models/props_urban/fence_cover001_128.mdl shelter fence (128u)
models/props_urban/fence_cover001_256.mdl shelter fence (256u)
models/props_fortifications/barricade_gate001_64_reference.mdl roadblock-single layer without handle (easy to use)
models/props_fortifications/barricade001_64_reference.mdl roadblock-single layer
models/props_fortifications/barricade001_128_reference.mdl roadblock-double layer
models/props_unique/airport/temp_barricade.mdl roadblock-airport
models/props_wasteland/exterior_fence002b.mdl Barbed wire fence - 1 wide skinny
models/props_wasteland/exterior_fence002c.mdl Barbed wire fence - 1 wide
models/props_wasteland/exterior_fence002d.mdl Barbed wire fence - 2 wide
models/props_wasteland/exterior_fence002e.mdl Barbed wire fence - 4 wide
models/props_street/police_barricade.mdl Police Barricade - 1 wide
models/props_street/police_barricade2.mdl Police barricade - 3 wide
models/props_street/police_barricade3.mdl Police Barricade - 6 wide
models/props_street/police_barricade_368in.mdl Police Barricade - 8 wide
models/props_street/police_barricade_496in.mdl Police Barricade - 10 wide
models/props_street/police_barricade4.mdl Iron Frame Barricade - 12 wide
models/lostcoast/props_wasteland/gate01a.mdl Iron fence gate a
models/lostcoast/props_wasteland/gate01b.mdl iron fence gate b
models/props_mill/elevator01_cage.mdl Mill Elevator-c4m2
models/props_mill/elevator01_cagedoor02.mdl Mill Elevator telescopic door-c4m2 (No Collision)
models/props_mill/elevator01_cagedoor.mdl Mill Elevator Cage door
models/props_mill/elevator01_framework.mdl Elevator shaft framework
models/props_mill/freightelevatorbutton01.mdl Mill Freight Elevator Button 1
models/props_mill/freightelevatorbutton02.mdl Mill Freight Elevator Button 2
models/props_street/barricade_door_01.mdl Military Agency Door-c9m1
models/props_urban/fence_768_collapsed.mdl Fence with covered shelter-c4m5
models/props_urban/gate_wall003_32.mdl Screening fence wall (32u)
models/props_urban/gate_wall003_64.mdl Screening fence wall (64u)
models/props_urban/gate_wall003_128.mdl Shelter fence wall (128u)
models/props_urban/gate_wall_gate003_64.mdl Wall Gate 3 (64u)
models/props_urban/wood_fence001_64.mdl Urban wooden fence a (64u)
models/props_urban/wood_fence001_128.mdl Urban wooden fence a (128u)
models/props_urban/wood_fence001_256.mdl Urban wooden fence a (256u)
models/props_urban/wood_fence002_64.mdl Urban wooden fence b (64u)
models/props_urban/wood_fence002_128.mdl Urban wooden fence b (128u)
models/props_urban/wood_fence002_256.mdl Urban wooden fence b (256u)
models/props_urban/wood_post001.mdl Urban Wood Post 1
models/props_urban/wood_post002.mdl Urban Wood Post 2
models/props_cemetery/cemetery_gate.mdl Cemetary Gate Barbed Wire with Spikes
models/props_cemetery/cemetery_gate_32.mdl Cemetary Gate Barbed Wire with Spikes (32u)
models/props_cemetery/cemetery_gate_64.mdl Cemetary Gate Barbed Wire with Spikes (64u)
models/props_cemetery/cemetery_gate_128.mdl Cemetary Gate Barbed Wire with Spikes (128u)
models/props_exteriors/roadsidefence_64.mdl Road fence-single layer (64u)
models/props_exteriors/roadsidefence_512.mdl road fence-eight layers (512u)
models/props_exteriors/fence_plastic001.mdl Plastic Fence
models/props_downtown/garden_gate.mdl Downtown Garden Gate
models/props/de_inferno/wood_fence.mdl De Inferno Wood Fence
models/props/de_inferno/wood_fence_end.mdl De Inferno Wood Fence End
models/props_urban/fence001_128.mdl Urban Chain Link Fence1 (128u)
models/props_urban/fence001_256.mdl Urban Chain Link Fence1 (256u)
models/props_urban/fence001_64.mdl Urban Chain Link Fence1 (64u)
models/props_urban/fence002_128.mdl Urban Chain Link Fence2 (128u)
models/props_urban/fence002_256.mdl Urban Chain Link Fence2 (256u)
models/props_urban/fence002_64.mdl Urban Chain Link Fence2 (64u)
models/props_urban/fence003_128.mdl Urban Chain Link Fence3 (128u)
models/props_urban/fence003_64.mdl Urban Chain Link Fence3 (64u)
models/props_urban/fence004_128.mdl Urban Chain Link Fence Frame (128u)
models/props_urban/fence004_256.mdl Urban Chain Link Fence Frame (256u)
models/props_urban/fence004_64.mdl Urban Fence Chain Link Frame (64u)
models/props_urban/fence_barbwire001_128.mdl Urban Barbwire Fence (128u)
models/props_urban/fence_barbwire001_256.mdl Urban Barbwire Fence (256u)
models/props_urban/fence_barbwire001_64.mdl Urban Barbwire Fence (64u)
models/props_urban/fence_post_barbwire001.mdl Urban Barbwire Fence Post
models/props_urban/fence_gate001_128.mdl Urban Fence Gate1 (128u)
models/props_urban/fence_gate001_256.mdl Urban Fence Gate1 (256u)
models/props_urban/fence_gate002_256.mdl Urban Fence Gate2 (256u)
models/props_urban/fence_gate003.mdl Urban Fence Gate3 (Small)
models/props_urban/fence_gate_post001.mdl Urban Chain Link Fence Gate Post 1
models/props_urban/fence_gate_post003.mdl Urban Chain Link Fence Gate Post 2
models/props_urban/fence_post001.mdl Urban Chain Link Fence Post 1
models/props_urban/fence_post002.mdl Urban Chain Link Fence Post 2
models/props_urban/fence_post003.mdl Urban Chain Link Fence Post 3
models/props_urban/gate_column001_32.mdl Urban Gate Column

View file

@ -0,0 +1,28 @@
Walls
models/props_update/brick_128.mdl brick wall/floor (128u)
models/props_update/brick_256.mdl brick wall/floor (256u)
models/props_update/concrete_128.mdl cement wall/floor (128u)
models/props_update/concrete_256.mdl cement wall/floor (256u)
models/props_update/plywood_128.mdl wooden wall/floor (128u)
models/props_update/plywood_256.mdl wooden wall/floor (256u)
models/props_update/whitebrick_128.mdl white brick wall (128u)
models/props_update/whitebrick_256.mdl white brick wall (256u)
models/props_update/wood_128.mdl wooden walls (128u)
models/props_update/wood_256.mdl wooden walls (256u)
models/props_urban/gate_wall001_64.mdl Urban Wall (64u)
models/props_urban/gate_wall001_128.mdl Urban Wall (128u)
models/props_urban/gate_wall001_256.mdl Urban Wall (256u)
models/props_urban/gate_wall002_128.mdl urban fence wall (128u)
models/props_unique/zombiebreakwallexteriorairport01_main.mdl Wallpaper - Airport
models/props_unique/zombiebreakwallexteriorairportoffices01_main.mdl Wallpaper - Airport Office
models/props_unique/zombiebreakwallhospitalexterior01_main.mdl Wallpaper - Hospital
models/lighthouse/props/wall_144_324.mdl Wall-144X(324u) (No Side)
models/props_interiors/constructionwalls02checkpoint.mdl steel building framing (with doorway)
models/props_interiors/constructionwalls03.mdl steel building framing
models/props_interiors/constructionwalls04_damage01.mdl Extra-long building steel column
models/props_cemetery/crypts_wall.mdl Thickened stone wall-Cemetery Exposed Brick
models/props_mill/locker_roof_collapsed01.mdl Mill Locker Roof Collapsed (no side)
models/props_mill/millwall_01.mdl Mill wall 1 (no side)
models/props_mill/millwall_02.mdl Mill wall 2 (no side)
models/props_mill/millwall_03.mdl Mill wall 3 (no side)
models/props_mill/column_01.mdl Mill Rebar Column

View file

@ -595,5 +595,67 @@
]
}
]
},
"truck-bridge-gap": {
"chance": 0.40000000596046448,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_vehicles/semi_trailer_wrecked.mdl",
"origin": [
-12307.5810546875,
-11925.724609375,
-349.92706298828125
],
"angles": [
4.0999965667724609,
72.799995422363281,
-2.0
]
}
]
}
]
},
"catwalk-pipes": {
"chance": 0.5,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_mill/pipeset08d_256_001a.mdl",
"origin": [
-12992.806640625,
-5664.62939453125,
-266.845703125
],
"angles": [
0.0,
0.0,
270.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_mill/pipeset08d_256_001a.mdl",
"origin": [
-13243.6201171875,
-5662.48095703125,
-267.79513549804688
],
"angles": [
0.0,
0.0,
270.0
]
}
]
}
]
}
}

View file

@ -524,6 +524,578 @@
]
}
]
},
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
-7604.6962890625,
-5517.0537109375,
-63.71875
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
-7600.89892578125,
-5628.1220703125,
-63.71875
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
-7598.435546875,
-5730.88330078125,
-63.718753814697266
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
-7599.41845703125,
-5829.40625,
-63.718753814697266
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
-7599.73095703125,
-5930.41748046875,
-63.718746185302734
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_exteriors/roadsidefence_64.mdl",
"origin": [
-7670.9248046875,
-5441.72509765625,
-96.096488952636719
],
"angles": [
0.0,
90.0,
-30.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_exteriors/roadsidefence_64.mdl",
"origin": [
-7715.326171875,
-5440.0615234375,
-125.46791076660156
],
"angles": [
0.0,
90.0,
-30.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_interiors/sheetrock_leaning.mdl",
"origin": [
-7834.50634765625,
-5506.349609375,
-247.73503112792969
],
"angles": [
0.0,
-270.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_exteriors/roadsidefence_64.mdl",
"origin": [
-7768.7626953125,
-5440.03125,
-158.68734741210938
],
"angles": [
0.0,
90.0,
-30.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_exteriors/roadsidefence_64.mdl",
"origin": [
-7824.25048828125,
-5441.51611328125,
-195.01101684570312
],
"angles": [
0.0,
90.0,
-30.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_equipment/metalladder002.mdl",
"origin": [
-8446.7109375,
-6000.96875,
-179.07974243164062
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props/cs_assault/forklift.mdl",
"origin": [
-8446.1474609375,
-5954.8544921875,
-321.01327514648438
],
"angles": [
0.0,
-90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_industrial/warehouse_shelf001.mdl",
"origin": [
-8764.8349609375,
-6118.96630859375,
-61.846946716308594
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_industrial/warehouse_shelf003.mdl",
"origin": [
-8538.37109375,
-6279.68115234375,
-63.222255706787109
],
"angles": [
0.0,
-90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_interiors/sheetrock_leaning.mdl",
"origin": [
-7712.74853515625,
-6103.77587890625,
-63.735023498535156
],
"angles": [
0.0,
-165.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props/cs_militia/shelves_wood.mdl",
"origin": [
-7655.509765625,
-6076.41162109375,
-61.889106750488281
],
"angles": [
0.0,
45.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_industrial/warehouse_shelf002.mdl",
"origin": [
-7701.6396484375,
-6118.47412109375,
-62.106662750244141
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/train_box_open.mdl",
"origin": [
-7822.83056640625,
-6486.45556640625,
-61.381694793701172
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/train_enginecar.mdl",
"origin": [
-7410.93994140625,
-6787.6025390625,
-61.410385131835938
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/train_flatcar.mdl",
"origin": [
-8124.68115234375,
-6636.7177734375,
-62.520648956298828
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/train_box.mdl",
"origin": [
-8475.91015625,
-6484.85595703125,
-62.520648956298828
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-7953.88037109375,
-6027.1240234375,
-50.131851196289062
],
"angles": [
-15.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-7959.54736328125,
-5806.42041015625,
-99.561187744140625
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_industrial/plywood_leaning.mdl",
"origin": [
-7823.16748046875,
-5862.0478515625,
-246.55105590820312
],
"angles": [
15.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_industrial/pallet_barrels_water01_docks.mdl",
"origin": [
-8305.1142578125,
-5699.38525390625,
-319.90985107421875
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "env_physics_blocker",
"origin": [
-7645.275390625,
-5453.0224609375,
-21.96875
],
"scale": [
10.0,
15.0,
100.0
]
},
{
"type": "light_dynamic",
"origin": [
-8442.83984375,
-5990.68310546875,
-80.129623413085938
],
"color": [
255,
255,
255,
1
],
"angles": [
0.0,
0.0,
0.0
],
"scale": [
400.0,
-1.0,
-1.0
]
},
{
"type": "infodecal",
"origin": [
-8508.3330078125,
-5999.96875,
-139.70254516601562
],
"model": "decals/checkpointarrow01_black.vmt"
},
{
"type": "infodecal",
"origin": [
-7578.3076171875,
-5344.03125,
-1.9795554876327515
],
"model": "decals/checkpointarrow01_black.vmt"
},
{
"type": "prop_dynamic",
"model": "models/props_equipment/light_floodlight.mdl",
"origin": [
-8609.4853515625,
-5886.58740234375,
-318.59130859375
],
"angles": [
0.0,
-30.0,
0.0
],
"properties": {
"int": {
"m_nSkin": 1
}
}
},
{
"type": "prop_dynamic",
"model": "models/props_equipment/light_floodlight.mdl",
"origin": [
-7772.57275390625,
-6078.6318359375,
-61.102703094482422
],
"angles": [
0.0,
-165.0,
0.0
],
"properties": {
"int": {
"m_nSkin": 1
}
}
},
{
"type": "light_dynamic",
"origin": [
-7789.453125,
-6090.96240234375,
-25.968757629394531
],
"color": [
255,
255,
255,
1
],
"angles": [
-162.0,
0.0,
0.0
],
"scale": [
400.0,
-1.0,
-1.0
]
}
],
"inputs": [
{
"hammerid": 286780,
"input": "_allow_ladder"
}
]
}
]
},
"start-help": {
"chance": 0.40000000596046448,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-11552.841796875,
-8238.443359375,
-461.36874389648438
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-11452.822265625,
-8187.95556640625,
-462.92050170898438
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-11321.1884765625,
-8188.3017578125,
-462.57418823242188
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_urban/metal_plate001.mdl",
"origin": [
-11188.369140625,
-8189.39599609375,
-462.95126342773438
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_c17/truss02h.mdl",
"origin": [
-11365.6318359375,
-8171.609375,
-480.19430541992188
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_c17/truss02h.mdl",
"origin": [
-11244.2041015625,
-8188.748046875,
-478.780517578125
],
"angles": [
0.0,
0.0,
0.0
]
}
]
}
]
}

View file

@ -0,0 +1,341 @@
{
"pills": {
"chance": 0.10000000149011612,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
},
{
"type": "weapon_pain_pills",
"model": "models/w_models/weapons/w_eq_painpills.mdl",
"origin": [
-2223.25439453125,
-5297.4228515625,
657.84283447265625
],
"angles": [
36.637165069580078,
166.42544555664062,
-85.725311279296875
]
}
]
}
]
},
"gascans": {
"chance": 0.80000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "_gascan",
"origin": [
-6051.14208984375,
-3448.0810546875,
10.876523017883301
],
"angles": [
-0.55249863862991333,
129.0628662109375,
0.0064697265625
]
},
{
"type": "_gascan",
"origin": [
-5950.7998046875,
-3225.01025390625,
10.882441520690918
],
"angles": [
-0.5578463077545166,
-139.19509887695312,
-0.124267578125
]
},
{
"type": "_gascan",
"origin": [
-4745.12109375,
-2358.740234375,
10.877493858337402
],
"angles": [
-0.58881288766860962,
-56.487579345703125,
-0.1336669921875
]
},
{
"type": "_gascan",
"origin": [
-4925.220703125,
-2751.919921875,
290.86605834960938
],
"angles": [
-0.55006474256515503,
-44.867576599121094,
0.007659912109375
]
},
{
"type": "_gascan",
"origin": [
-3909.123291015625,
-2742.46826171875,
290.86465454101562
],
"angles": [
-0.55862104892730713,
-159.15614318847656,
0.0079345703125
]
},
{
"type": "_gascan",
"origin": [
-3879.3017578125,
-3364.2548828125,
290.87225341796875
],
"angles": [
-0.55406862497329712,
-47.913330078125,
0.0017852783203125
]
},
{
"type": "_gascan",
"origin": [
-2867.53466796875,
-3212.300048828125,
290.868408203125
],
"angles": [
-0.53946495056152344,
103.97676849365234,
0.0077972412109375
]
},
{
"type": "_gascan",
"origin": [
-3061.08349609375,
-3134.86376953125,
10.877670288085938
],
"angles": [
-0.57504987716674805,
-77.274543762207031,
-0.1275634765625
]
},
{
"type": "_gascan",
"origin": [
-3607.03955078125,
-3158.387939453125,
10.877679824829102
],
"angles": [
-0.57509583234786987,
-121.18537902832031,
-0.12750244140625
]
},
{
"type": "_gascan",
"origin": [
-4482.93115234375,
-4446.20458984375,
10.853196144104004
],
"angles": [
-0.72719091176986694,
54.255725860595703,
-0.16156005859375
]
},
{
"type": "_gascan",
"origin": [
-4020.397705078125,
-4442.953125,
10.86365795135498
],
"angles": [
0.3856024444103241,
114.11133575439453,
-0.273193359375
]
},
{
"type": "_gascan",
"origin": [
-5399.42822265625,
-4438.22119140625,
10.882131576538086
],
"angles": [
-0.54621058702468872,
33.001979827880859,
-0.1214599609375
]
},
{
"type": "_gascan",
"origin": [
-5424.62451171875,
-4431.45849609375,
290.86849975585938
],
"angles": [
-0.868499755859375,
72.193069458007812,
0.2503509521484375
]
}
]
}
]
},
"PEANUT": {
"chance": 1.0,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_fairgrounds/lil'peanut_cutout001.mdl",
"origin": [
-4683.3173828125,
-2287.525634765625,
303.778564453125
],
"angles": [
0.0,
-90.0,
0.0
]
}
]
}
]
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -22,5 +22,251 @@
]
}
]
},
"trailer": {
"chance": 0.30000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_debris/concrete_debris128pile001b.mdl",
"origin": [
-5020.86962890625,
6377.85693359375,
641.72576904296875
],
"angles": [
0.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/hmmwv.mdl",
"origin": [
-4926.7568359375,
6393.20068359375,
626.56927490234375
],
"angles": [
-3.8999967575073242,
61.0,
9.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_debris/concrete_debris128pile001a.mdl",
"origin": [
-4907.00537109375,
6379.3125,
701.50091552734375
],
"angles": [
19.80000114440918,
-10.699999809265137,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/semi_trailer_wrecked.mdl",
"origin": [
-5159.9794921875,
6288.13427734375,
516.46624755859375
],
"angles": [
0.0,
118.30000305175781,
-5.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_debris/concrete_debris128pile001a.mdl",
"origin": [
-4939.30126953125,
6397.275390625,
697.10382080078125
],
"angles": [
4.4000000953674316,
0.0,
0.0
]
}
]
}
]
},
"bus": {
"chance": 0.30000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_vehicles/bus01_2.mdl",
"origin": [
-3170.48095703125,
6297.6298828125,
640.4088134765625
],
"angles": [
-23.000001907348633,
49.799995422363281,
-20.0
]
}
]
}
]
},
"humvee": {
"chance": 0.30000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_vehicles/hmmwv.mdl",
"origin": [
4218.40283203125,
6309.74951171875,
455.75555419921875
],
"angles": [
0.0,
-93.300003051757812,
0.0
]
}
]
}
]
},
"car-block": {
"chance": 0.30000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_vehicles/cara_95sedan.mdl",
"origin": [
4680.36962890625,
6451.8359375,
598.89410400390625
],
"angles": [
-16.500001907348633,
113.90000152587891,
-3.0
]
}
]
}
]
},
"bus-down-alt": {
"chance": 0.40000000596046448,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_vehicles/cara_84sedan.mdl",
"origin": [
9448.177734375,
2465.4091796875,
402.39703369140625
],
"angles": [
-19.69999885559082,
-7.8000001907348633,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_vehicles/cara_95sedan_wrecked.mdl",
"origin": [
9574.169921875,
2354.686279296875,
230.94760131835938
],
"angles": [
-3.7000000476837158,
66.599998474121094,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
9241.9619140625,
2593.072998046875,
395.70574951171875
],
"angles": [
-1.5000001192092896,
-16.5,
3.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
9209.5185546875,
2495.00341796875,
387.2938232421875
],
"angles": [
-1.5000001192092896,
-16.5,
3.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_128_reference.mdl",
"origin": [
9276.5849609375,
2693.54833984375,
405.56076049804688
],
"angles": [
-1.5000001192092896,
-16.5,
3.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_fortifications/barricade001_64_reference.mdl",
"origin": [
9286.923828125,
2788.736328125,
409.21328735351562
],
"angles": [
0.0,
-22.400001525878906,
5.0
]
}
]
}
]
}
}

View file

@ -1004,6 +1004,61 @@
69.000007629394531,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_street/concertinawire128.mdl",
"origin": [
1089.169921875,
1763.4981689453125,
291.31658935546875
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_street/concertinawire128.mdl",
"origin": [
964.45440673828125,
1765.302490234375,
291.97311401367188
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_street/concertinawire128.mdl",
"origin": [
837.82415771484375,
1765.9117431640625,
289.5538330078125
],
"angles": [
0.0,
90.0,
0.0
]
},
{
"type": "env_physics_blocker",
"origin": [
752.350830078125,
2041.630615234375,
548.03125
],
"scale": [
15.0,
240.0,
100.0
]
}
]
}
@ -1369,7 +1424,7 @@
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"type": "prop_dynamic_override",
"model": "models/props_junk/gnome.mdl",
"origin": [
-1365.762451171875,
@ -1385,5 +1440,123 @@
]
}
]
},
"bar-block": {
"chance": 0.30000001192092896,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_03.mdl",
"origin": [
273.46566772460938,
-357.96719360351562,
0.3364105224609375
],
"angles": [
90.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_03.mdl",
"origin": [
273.00442504882812,
-405.81011962890625,
7.7817878723144531
],
"angles": [
90.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_01.mdl",
"origin": [
249.58372497558594,
-385.9383544921875,
-25.917247772216797
],
"angles": [
90.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_01.mdl",
"origin": [
253.77641296386719,
-356.08816528320312,
-4.7134323120117188
],
"angles": [
90.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_01.mdl",
"origin": [
253.83631896972656,
-362.62399291992188,
55.695259094238281
],
"angles": [
90.0,
0.0,
0.0
]
},
{
"type": "prop_dynamic",
"model": "models/props_highway/plywood_01.mdl",
"origin": [
252.20606994628906,
-385.1119384765625,
46.342216491699219
],
"angles": [
90.0,
0.0,
0.0
]
}
]
}
]
},
"sedan": {
"chance": 0.20000000298023224,
"variants": [
{
"weight": 1,
"entities": [
{
"type": "_car_physics",
"model": "models/props_vehicles/cara_95sedan.mdl",
"origin": [
11.371078491210938,
-84.446060180664062,
-2.687330961227417
],
"angles": [
0.0,
0.0,
0.0
]
}
]
}
]
}
}

View file

@ -297,12 +297,12 @@
"type": "prop_dynamic",
"model": "models/props_c17/metalladder001.mdl",
"origin": [
3513.515673828125,
3513.5156738281248,
3324.55859375,
84.583740234375
],
"angles": [
0.3999999761581421,
0.39999997615814209,
-91.400001525878906,
0.0
]
@ -511,7 +511,7 @@
"type": "prop_dynamic",
"model": "models/props_vehicles/bus01.mdl",
"origin": [
7087.00927734375,
7099.00927734375,
5887.7353515625,
41.365642547607422
],
@ -576,6 +576,19 @@
0.0,
0.0
]
},
{
"type": "env_physics_blocker",
"origin": [
7155.35693359375,
5903.732421875,
134.93994140625
],
"scale": [
18.0,
240.0,
40.0
]
}
]
}

Binary file not shown.

Binary file not shown.

View file

@ -489,24 +489,9 @@ void DirectorSpawn(specialType special, int player = -1) {
}
}
// Finds a player that is suitable (lowest intensity)
// TODO: biased random (lower intensity : bias)
// dice roll, #sides = #players, sort list of players by intensity
// then use biased left dice, therefore lower intensity = higher random weight
int g_iLastVictim;
int GetSuitableVictim() {
// TODO: randomize?
return GetRandomSurvivor(1, -1);
// ArrayList survivors = new ArrayList(2);
// for(int i = 1; i <= MaxClients; i++) {
// if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
// int index = survivors.Push(i);
// survivors.Set(index, 1, L4D_GetPlayerIntensity(i));
// }
// }
// // Soe
// survivors.SortCustom()
int victim = -1;
float lowestIntensity = 0.0;
for(int i = 1; i <= MaxClients; i++) {

View file

@ -46,7 +46,7 @@ stock int CreateEnvBlockerScaled(const char[] entClass, const float pos[3], cons
int entity = CreateEntityByName(entClass);
DispatchKeyValue(entity, "targetname", ENT_BLOCKER_NAME);
DispatchKeyValue(entity, "initialstate", "1");
DispatchKeyValue(entity, "BlockType", "0");
DispatchKeyValueInt(entity, "BlockType", StrEqual(entClass, "env_physics_blocker") ? 4 : 0);
static float mins[3];
mins = scale;
NegateVector(mins);
@ -85,8 +85,8 @@ enum struct PortalData {
float portalOffsets[3];
}
static AnyMap portals;
stock int CreatePortal(PortalType type, const char model[64], const float pos[3], const float offset[3] = { 40.0, 40.0, 0.0 }, const float scale[3] = { 5.0, 5.0, 5.0 }) {
#pragma unused model
int entity = CreateEntityByName("trigger_multiple");
if(entity == -1) return -1;
DispatchKeyValue(entity, "spawnflags", "513");
@ -160,11 +160,12 @@ stock void ClearPortalData() {
portals.Clear();
}
stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR) {
stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR, bool hasCollision = true) {
int entity = CreateEntityByName(entClass);
if(entity == -1) return -1;
DispatchKeyValue(entity, "model", model);
DispatchKeyValue(entity, "solid", "6");
if(hasCollision)
DispatchKeyValue(entity, "solid", "6");
DispatchKeyValue(entity, "targetname", ENT_PROP_NAME);
DispatchKeyValue(entity, "disableshadows", "1");
TeleportEntity(entity, pos, ang, vel);

View file

@ -884,6 +884,7 @@ stock bool IsAreaClear(const float pos[3], const float ang[3], const float minBo
}
stock Action Timer_KillEntity(Handle h, int entity) {
RemoveEntity(entity);
return Plugin_Handled;
}

View file

@ -1,3 +1,27 @@
#define WINDSHIELD_LIST_COUNT 1
char VEHICLE_MODEL_WINDSHIELD_KEY[WINDSHIELD_LIST_COUNT][] = {
"models/props_vehicles/cement_truck01.mdl"
};
char VEHICLE_MODEL_WINDSHIELD_VAL[WINDSHIELD_LIST_COUNT][] = {
"models/props_vehicles/cement_truck01_windows.mdl"
};
bool GetWindshieldModel(const char[] vehicleModel, char[] model, int modelSize) {
bool found = false;
for(int i = 0; i < WINDSHIELD_LIST_COUNT; i++) {
if(StrEqual(VEHICLE_MODEL_WINDSHIELD_KEY[i], vehicleModel)) {
strcopy(model, modelSize, VEHICLE_MODEL_WINDSHIELD_VAL[i]);
found = true;
break;
}
}
if(!found) {
strcopy(model, modelSize, vehicleModel);
ReplaceString(model, modelSize, ".mdl", "_glass.mdl");
}
return PrecacheModel(model);
}
int SpawnCar(VariantEntityData entity) {
if(entity.model[0] == '\0') {
LogError("Missing model for entity with type \"%s\"", entity.type);
@ -12,14 +36,12 @@ int SpawnCar(VariantEntityData entity) {
}
char glassModel[64];
strcopy(glassModel, sizeof(glassModel), entity.model);
ReplaceString(glassModel, sizeof(glassModel), ".mdl", "_glass.mdl");
if(StrEqual(entity.type, "_car_physics")) {
vehicle = CreateProp("prop_physics", entity.model, entity.origin, entity.angles);
} else {
vehicle = CreateProp("prop_dynamic", entity.model, entity.origin, entity.angles);
}
if(PrecacheModel(glassModel)) {
if(GetWindshieldModel(entity.model, glassModel, sizeof(glassModel))) {
int glass = CreateProp("prop_dynamic", glassModel, entity.origin, entity.angles);
if(glass != -1) {
SetVariantString("!activator");

View file

@ -0,0 +1,599 @@
#define MAX_SCENE_NAME_LENGTH 32
#define MAX_INPUTS_CLASSNAME_LENGTH 64
int DEFAULT_COLOR[4] = { 255, 255, 255, 255 };
MapData g_MapData; // The global map data
SceneSelection g_selection; // The selected scenes from the global map data
BuilderData g_builder; // The global instance of the builder
ArrayList g_mapTraverseSelectionStack; // For maps that traverse backwards, holds record of the selected scenes so they can be re-applied
int g_ropeIndex; // Unique id for ropes on spawn, is reset to 0 for every new spawn attempt
ArrayList g_gascanRespawnQueue; // Queue that gascan respawns pop from to respawn to
AnyMap g_gascanSpawners; // Mapping of <entity index, GascanSpawnerData>, for when a can is destroyed it can be respawned in position
int g_iLaserIndex;
public void InitGlobals() {
g_gascanSpawners = new AnyMap();
g_mapTraverseSelectionStack = new ArrayList(sizeof(TraverseData));
}
enum struct TraverseData {
char map[64];
ArrayList selection;
}
methodmap SceneSelection < ArrayList {
public SceneSelection() {
ArrayList selectedScenes = new ArrayList(sizeof(SelectedSceneData));
return view_as<SceneSelection>(selectedScenes);
}
property int Count {
public get() {
return (view_as<ArrayList>(this)).Length;
}
}
public void Cleanup() {
delete this;
}
public void Activate(MapData data, int flags = 0) {
g_ropeIndex = 0;
SelectedSceneData aScene;
SceneData scene;
SceneVariantData choice;
ArrayList list = view_as<ArrayList>(this);
for(int i = 0; i < list.Length; i++) {
list.GetArray(i, aScene);
Log("Activating scene \"%s\" with %d variants", aScene.name, aScene.selectedVariantIndexes.Length);
// Fetch the scene that aScene marks
if(!data.scenesKv.GetArray(aScene.name, scene, sizeof(scene))) {
Log("WARN: Selected scene \"%s\" not found, skipping", aScene.name);
continue;
}
for(int v = 0; v < aScene.selectedVariantIndexes.Length; v++) {
int variantIndex = aScene.selectedVariantIndexes.Get(v);
scene.variants.GetArray(variantIndex, choice);
activateVariant(choice, flags);
}
}
}
public void Get(int sceneIndex, SelectedSceneData scene) {
(view_as<ArrayList>(this)).GetArray(sceneIndex, scene);
}
property ArrayList List {
public get() {
return view_as<ArrayList>(this);
}
}
public void AddScene(SelectedSceneData aScene) {
view_as<ArrayList>(this).PushArray(aScene);
}
}
void StoreTraverseSelection(const char[] name, SceneSelection selection) {
// Pushes selection and map to the stack
TraverseData data;
strcopy(data.map, sizeof(data.map), name);
data.selection = selection.List.Clone();
g_mapTraverseSelectionStack.PushArray(data);
}
bool PopTraverseSelection(TraverseData data) {
if(g_mapTraverseSelectionStack.Length == 0) {
Log("WARN: PopTraverseSelection() called but stack is empty");
return false;
}
int index = g_mapTraverseSelectionStack.Length - 1;
g_mapTraverseSelectionStack.GetArray(index, data);
g_mapTraverseSelectionStack.Erase(index);
return true;
}
void ClearTraverseStack() {
TraverseData trav;
for(int i = 0; i < g_mapTraverseSelectionStack.Length; i++) {
g_mapTraverseSelectionStack.GetArray(i, trav, sizeof(trav));
delete trav.selection;
}
g_mapTraverseSelectionStack.Clear();
}
enum struct SelectedSceneData {
char name[MAX_SCENE_NAME_LENGTH];
ArrayList selectedVariantIndexes;
}
enum struct GascanSpawnerData {
float origin[3];
float angles[3];
}
enum struct MapData {
StringMap scenesKv;
ArrayList scenes;
ArrayList lumpEdits;
ArrayList activeScenes;
ArrayList gascanSpawners;
StringMap groups;
void Cleanup() {
SceneData scene;
for(int i = 0; i < this.scenes.Length; i++) {
this.scenes.GetArray(i, scene);
scene.Cleanup();
}
delete this.scenes;
delete this.scenesKv;
delete this.lumpEdits;
delete this.activeScenes;
delete this.gascanSpawners;
delete this.groups;
}
SceneSelection GenerateSelection(int flags) {
return selectScenes(this, flags);
}
bool ApplySelection(SceneSelection selection, int flags) {
Profiler profiler = new Profiler();
profiler.Start();
selection.Activate(this, flags);
spawnGascans(this);
profiler.Stop();
// _ropeIndex = 0;
Log("Done applying selection in %.4f seconds", profiler.Time);
return true;
}
bool IsLoaded() {
return this.scenes != null;
}
}
enum loadFlags {
FLAG_NONE = 0,
FLAG_ALL_SCENES = 1, // Pick all scenes, no random chance
FLAG_ALL_VARIANTS = 2, // Pick all variants (for debug purposes),
FLAG_REFRESH = 4, // Load data bypassing cache
FLAG_FORCE_ACTIVE = 8, // Similar to ALL_SCENES, bypasses % chance
FLAG_IGNORE_TRAVERSE_STORE = 16 // Do not load stored selection from the g_mapTraverseSelections
}
enum struct BuilderData {
JSONObject mapData;
JSONObject selectedSceneData;
char selectedSceneId[64];
JSONObject selectedVariantData;
int selectedVariantIndex;
bool IsLoaded() {
return this.mapData != null;
}
void Cleanup() {
this.selectedSceneData = null;
this.selectedVariantData = null;
this.selectedVariantIndex = -1;
this.selectedSceneId[0] = '\0';
if(this.mapData != null)
delete this.mapData;
// JSONcleanup_and_delete(this.mapData);
}
bool SelectScene(const char[] group) {
if(!g_builder.mapData.HasKey(group)) return false;
this.selectedSceneData = view_as<JSONObject>(g_builder.mapData.Get(group));
strcopy(this.selectedSceneId, sizeof(this.selectedSceneId), group);
return true;
}
/**
* Select a variant, enter -1 to not select any (scene's entities)
*/
bool SelectVariant(int index = -1) {
if(this.selectedSceneData == null) LogError("SelectVariant called, but no group selected");
JSONArray variants = view_as<JSONArray>(this.selectedSceneData.Get("variants"));
if(index >= variants.Length) return false;
else if(index < -1) return false;
else if(index > -1) {
this.selectedVariantData = view_as<JSONObject>(variants.Get(index));
} else {
this.selectedVariantData = null;
}
this.selectedVariantIndex = index;
return true;
}
void AddEntity(int entity, ExportType exportType = Export_Model) {
JSONObject entityData = ExportEntity(entity, exportType);
this.AddEntityData(entityData);
}
void AddEntityData(JSONObject entityData) {
JSONArray entities;
if(g_builder.selectedVariantData == null) {
// Create <scene>.entities if doesn't exist:
if(!g_builder.selectedSceneData.HasKey("entities")) {
g_builder.selectedSceneData.Set("entities", new JSONArray());
}
entities = view_as<JSONArray>(g_builder.selectedSceneData.Get("entities"));
} else {
entities = view_as<JSONArray>(g_builder.selectedVariantData.Get("entities"));
}
entities.Push(entityData);
}
}
enum struct SceneData {
char name[MAX_SCENE_NAME_LENGTH];
float chance;
char group[MAX_SCENE_NAME_LENGTH];
ArrayList variants;
void Cleanup() {
SceneVariantData choice;
for(int i = 0; i < this.variants.Length; i++) {
this.variants.GetArray(i, choice);
choice.Cleanup();
}
delete this.variants;
}
}
enum struct SceneVariantData {
int weight;
ArrayList inputsList;
ArrayList entities;
ArrayList forcedScenes;
void Cleanup() {
delete this.inputsList;
VariantEntityData entity;
for(int i = 0; i < this.entities.Length; i++) {
this.entities.GetArray(i, entity, sizeof(entity));
entity.Cleanup();
}
delete this.entities;
delete this.forcedScenes;
}
}
enum propertyType {
PROPERTY_NONE = -1,
PROPERTY_STRING,
PROPERTY_INTEGER,
PROPERTY_FLOAT
}
// This is horrible but we need a way to know what the type of the netprop to set is
enum struct PropertyStore {
JSONObject intKv;
JSONObject stringKv;
JSONObject floatKv;
void Cleanup() {
if(this.intKv != null) delete this.intKv;
if(this.stringKv != null) delete this.stringKv;
if(this.floatKv != null) delete this.floatKv;
}
bool GetInt(const char[] name, int &value) {
if(this.intKv == null) return false;
if(!this.intKv.HasKey(name)) return false;
value = this.intKv.GetInt(name);
return true;
}
bool GetString(const char[] name, char[] buffer, int maxlen) {
if(this.stringKv == null) return false;
if(!this.stringKv.HasKey(name)) return false;
this.stringKv.GetString(name, buffer, maxlen);
return true;
}
bool GetFloat(const char[] name, float &value) {
if(this.floatKv == null) return false;
if(!this.floatKv.HasKey(name)) return false;
value = this.floatKv.GetFloat(name);
return true;
}
propertyType GetPropertyType(const char[] key) {
if(this.intKv != null && this.intKv.HasKey(key)) return PROPERTY_INTEGER;
if(this.floatKv != null && this.floatKv.HasKey(key)) return PROPERTY_FLOAT;
if(this.stringKv != null && this.stringKv.HasKey(key)) return PROPERTY_STRING;
return PROPERTY_NONE;
}
bool HasAny() {
return this.intKv != null || this.floatKv != null || this.stringKv != null;
}
ArrayList Keys() {
char key[128];
ArrayList list = new ArrayList(ByteCountToCells(128));
JSONObjectKeys keys;
if(this.stringKv != null) {
keys = this.stringKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
list.PushString(key);
}
delete keys;
}
if(this.intKv != null) {
keys = this.intKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
list.PushString(key);
}
delete keys;
}
if(this.floatKv != null) {
keys = this.floatKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
list.PushString(key);
}
delete keys;
}
return list;
}
StringMap Entries() {
char key[128];
StringMap kv = new StringMap();
JSONObjectKeys keys;
if(this.stringKv != null) {
keys = this.stringKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
kv.SetValue(key, PROPERTY_STRING);
}
delete keys;
}
if(this.intKv != null) {
keys = this.intKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
kv.SetValue(key, PROPERTY_INTEGER);
}
delete keys;
}
if(this.floatKv != null) {
keys = this.floatKv.Keys()
while(keys.ReadKey(key, sizeof(key))) {
kv.SetValue(key, PROPERTY_FLOAT);
}
delete keys;
}
return kv;
}
}
enum struct VariantEntityData {
char type[32];
char model[128];
char targetname[128];
float origin[3];
float angles[3];
float scale[3];
int color[4];
ArrayList keyframes;
PropertyStore properties;
JSONObject propertiesInt;
JSONObject propertiesString;
JSONObject propertiesFloat;
void Cleanup() {
if(this.keyframes != null) {
delete this.keyframes;
}
this.properties.Cleanup();
}
void ApplyProperties(int entity) {
if(!this.properties.HasAny()) return;
char key[64], buffer[128];
ArrayList keys = this.properties.Keys();
for(int i = 0; i < keys.Length; i++) {
keys.GetString(i, key, sizeof(key));
// Only want to apply netprops (m_ prefix)
if(key[0] == 'm' && key[1] == '_') {
propertyType type = this.properties.GetPropertyType(key);
Debug("netprop %s type %d", key, type);
switch(type) {
case PROPERTY_STRING: {
this.properties.GetString(key, buffer, sizeof(buffer));
Debug("Applying netprop %s (val=%s) on %d", key, buffer, entity);
SetEntPropString(entity, Prop_Send, key, buffer);
break;
}
case PROPERTY_INTEGER: {
int val;
this.properties.GetInt(key, val);
Debug("Applying netprop %s (val=%d) on %d", key, val, entity);
SetEntProp(entity, Prop_Send, key, val);
break;
}
case PROPERTY_FLOAT: {
float val;
this.properties.GetFloat(key, val);
Debug("Applying netprop %s (val=%f) on %d", key, val, entity);
SetEntPropFloat(entity, Prop_Send, key, val);
break;
}
}
}
}
delete keys;
}
}
enum InputType {
Input_Classname,
Input_Targetname,
Input_HammerId
}
enum struct VariantInputData {
char name[MAX_INPUTS_CLASSNAME_LENGTH];
InputType type;
char input[64];
void Trigger() {
int entity = -1;
switch(this.type) {
case Input_Classname: {
while((entity = FindEntityByClassname(entity, this.name)) != INVALID_ENT_REFERENCE) {
this._trigger(entity);
}
}
case Input_Targetname: {
char targetname[64];
int count = 0;
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) {
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
if(StrEqual(targetname, this.name)) {
this._trigger(entity);
count++;
}
}
if(count == 0) {
PrintToServer("[Randomizer::WARN] Input TargetName=\"%s\" matched 0 entties", this.name);
}
}
case Input_HammerId: {
int targetId = StringToInt(this.name);
int count = 0;
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) {
int hammerId = GetEntProp(entity, Prop_Data, "m_iHammerID");
if(hammerId == targetId ) {
this._trigger(entity);
count++;
break;
}
}
if(count == 0) {
PrintToServer("[Randomizer::WARN] Input HammerId=%d matched 0 entties", targetId);
}
}
}
}
void _trigger(int entity) {
if(entity > 0 && IsValidEntity(entity)) {
if(StrEqual(this.input, "_allow_ladder")) {
if(HasEntProp(entity, Prop_Send, "m_iTeamNum")) {
SetEntProp(entity, Prop_Send, "m_iTeamNum", 0);
} else {
Log("Warn: Entity (%d) with id \"%s\" has no teamnum for \"_allow_ladder\"", entity, this.name);
}
} else if(StrEqual(this.input, "_lock")) {
AcceptEntityInput(entity, "Close");
AcceptEntityInput(entity, "Lock");
} else if(StrEqual(this.input, "_lock_nobreak")) {
AcceptEntityInput(entity, "Close");
AcceptEntityInput(entity, "Lock");
AcceptEntityInput(entity, "SetUnbreakable");
} else {
char cmd[32];
// Split input "a b" to a with variant "b"
int len = SplitString(this.input, " ", cmd, sizeof(cmd));
if(len > -1) {
SetVariantString(this.input[len]);
AcceptEntityInput(entity, cmd);
Debug("_trigger(%d): %s (v=%s)", entity, cmd, this.input[len]);
} else {
Debug("_trigger(%d): %s", entity, this.input);
AcceptEntityInput(entity, this.input);
}
}
}
}
}
enum struct LumpEditData {
char name[MAX_INPUTS_CLASSNAME_LENGTH];
InputType type;
char action[32];
char value[64];
int _findLumpIndex(int startIndex = 0, EntityLumpEntry entry) {
int length = EntityLump.Length();
char val[64];
Debug("Scanning for \"%s\" (type=%d)", this.name, this.type);
for(int i = startIndex; i < length; i++) {
entry = EntityLump.Get(i);
int index = entry.FindKey("hammerid");
if(index != -1) {
entry.Get(index, "", 0, val, sizeof(val));
if(StrEqual(val, this.name)) {
return i;
}
}
index = entry.FindKey("classname");
if(index != -1) {
entry.Get(index, "", 0, val, sizeof(val));
Debug("%s vs %s", val, this.name);
if(StrEqual(val, this.name)) {
return i;
}
}
index = entry.FindKey("targetname");
if(index != -1) {
entry.Get(index, "", 0, val, sizeof(val));
if(StrEqual(val, this.name)) {
return i;
}
}
delete entry;
}
Log("Warn: Could not find any matching lump for \"%s\" (type=%d)", this.name, this.type);
return -1;
}
void Trigger() {
int index = 0;
EntityLumpEntry entry;
while((index = this._findLumpIndex(index, entry) != -1)) {
// for(int i = 0; i < entry.Length; i++) {
// entry.Get(i, a, sizeof(a), v, sizeof(v));
// Debug("%s=%s", a, v);
// }
this._trigger(entry);
}
}
void _updateKey(EntityLumpEntry entry, const char[] key, const char[] value) {
int index = entry.FindKey(key);
if(index != -1) {
Debug("update key %s = %s", key, value);
entry.Update(index, key, value);
}
}
void _trigger(EntityLumpEntry entry) {
if(StrEqual(this.action, "setclassname")) {
this._updateKey(entry, "classname", this.value);
}
delete entry;
}
}

View file

@ -0,0 +1,268 @@
public bool LoadGlobalMapData(const char[] map, int flags) {
Cleanup();
g_selection = null;
return ParseMapData(g_MapData, map, flags);
}
public JSONObject LoadMapJson(const char[] map) {
Debug("Loading config for %s", map);
char filePath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, filePath, sizeof(filePath), "data/randomizer/%s.json", map);
if(!FileExists(filePath)) {
Log("No map config file (data/randomizer/%s.json), not loading", map);
return null;
}
JSONObject data = JSONObject.FromFile(filePath);
if(data == null) {
LogError("Could not parse map config file (data/randomizer/%s.json)", map);
return null;
}
return data;
}
public void SaveMapJson(const char[] map, JSONObject json) {
Debug("Saving config for %s", map);
char filePath[PLATFORM_MAX_PATH], filePathTemp[PLATFORM_MAX_PATH];
BuildPath(Path_SM, filePathTemp, sizeof(filePath), "data/randomizer/%s.json.tmp", map);
BuildPath(Path_SM, filePath, sizeof(filePath), "data/randomizer/%s.json", map);
json.ToFile(filePathTemp, JSON_INDENT(4));
RenameFile(filePath, filePathTemp);
SetFilePermissions(filePath, FPERM_U_WRITE | FPERM_U_READ | FPERM_G_WRITE | FPERM_G_READ | FPERM_O_READ);
}
/// Parses map data into first parameter, bool for success
public bool ParseMapData(MapData data, const char[] map, int flags) {
JSONObject json = LoadMapJson(map);
if(json == null) {
return false;
}
Debug("Starting parsing json data");
data.scenes = new ArrayList(sizeof(SceneData));
data.scenesKv = new StringMap();
data.lumpEdits = new ArrayList(sizeof(LumpEditData));
Profiler profiler = new Profiler();
profiler.Start();
JSONObjectKeys iterator = json.Keys();
char key[32];
while(iterator.ReadKey(key, sizeof(key))) {
if(key[0] == '_') {
if(StrEqual(key, "_lumps")) {
JSONArray lumpsList = view_as<JSONArray>(json.Get(key));
if(lumpsList != null) {
for(int l = 0; l < lumpsList.Length; l++) {
loadLumpData(data.lumpEdits, view_as<JSONObject>(lumpsList.Get(l)));
}
}
} else {
Debug("Unknown special entry \"%s\", skipping", key);
}
} else {
// if(data.GetType(key) != JSONType_Object) {
// Debug("Invalid normal entry \"%s\" (not an object), skipping", key);
// continue;
// }
JSONObject scene = view_as<JSONObject>(json.Get(key));
// Parses scene data and inserts to scenes
loadScene(data, key, scene);
}
}
delete json;
data.groups = new StringMap();
getSceneGroups(data, data.groups);
profiler.Stop();
Log("Parsed map %s(%d) in %.4f seconds (%d scenes)", map, flags, profiler.Time, data.scenes.Length);
delete profiler;
return true;
}
void getSceneGroups(MapData data, StringMap groups) {
ArrayList groupList;
SceneData scene;
for(int i = 0; i < data.scenes.Length; i++) {
data.scenes.GetArray(i, scene);
if(scene.group[0] != '\0') {
// Load it into group list
if(!groups.GetValue(scene.group, groupList)) {
groupList = new ArrayList();
}
groupList.Push(i);
groups.SetValue(scene.group, groupList);
}
}
}
void loadScene(MapData data, const char key[MAX_SCENE_NAME_LENGTH], JSONObject sceneData) {
SceneData scene;
scene.name = key;
scene.chance = sceneData.GetFloat("chance");
if(scene.chance < 0.0 || scene.chance > 1.0) {
LogError("Scene \"%s\" has invalid chance (%f)", scene.name, scene.chance);
return;
} else if(!sceneData.HasKey("variants")) {
ThrowError("Failed to load: Scene \"%s\" has missing \"variants\" array", scene.name);
return;
}
// TODO: load "entities", merge with choice.entities
sceneData.GetString("group", scene.group, sizeof(scene.group));
scene.variants = new ArrayList(sizeof(SceneVariantData));
JSONArray entities;
if(sceneData.HasKey("entities")) {
entities = view_as<JSONArray>(sceneData.Get("entities"));
}
// Load all variants
JSONArray variants = view_as<JSONArray>(sceneData.Get("variants"));
for(int i = 0; i < variants.Length; i++) {
// Parses choice and loads to scene.choices
loadChoice(scene, view_as<JSONObject>(variants.Get(i)), entities);
}
data.scenes.PushArray(scene);
data.scenesKv.SetArray(scene.name, scene, sizeof(scene));
}
void loadChoice(SceneData scene, JSONObject choiceData, JSONArray extraEntities) {
SceneVariantData choice;
choice.weight = choiceData.HasKey("weight") ? choiceData.GetInt("weight") : 1;
choice.entities = new ArrayList(sizeof(VariantEntityData));
choice.inputsList = new ArrayList(sizeof(VariantInputData));
choice.forcedScenes = new ArrayList(ByteCountToCells(MAX_SCENE_NAME_LENGTH));
// Load in any variant-based entities
if(choiceData.HasKey("entities")) {
JSONArray entities = view_as<JSONArray>(choiceData.Get("entities"));
for(int i = 0; i < entities.Length; i++) {
// Parses entities and loads to choice.entities
loadChoiceEntity(choice.entities, view_as<JSONObject>(entities.Get(i)));
}
delete entities;
}
// Load in any entities that the scene has
if(extraEntities != null) {
for(int i = 0; i < extraEntities.Length; i++) {
// Parses entities and loads to choice.entities
loadChoiceEntity(choice.entities, view_as<JSONObject>(extraEntities.Get(i)));
}
// delete extraEntities;
}
// Load all inputs
if(choiceData.HasKey("inputs")) {
JSONArray inputsList = view_as<JSONArray>(choiceData.Get("inputs"));
for(int i = 0; i < inputsList.Length; i++) {
loadChoiceInput(choice.inputsList, view_as<JSONObject>(inputsList.Get(i)));
}
delete inputsList;
}
if(choiceData.HasKey("force_scenes")) {
JSONArray scenes = view_as<JSONArray>(choiceData.Get("force_scenes"));
char sceneId[32];
for(int i = 0; i < scenes.Length; i++) {
scenes.GetString(i, sceneId, sizeof(sceneId));
choice.forcedScenes.PushString(sceneId);
Debug("scene %s: require %s", scene.name, sceneId);
}
delete scenes;
}
scene.variants.PushArray(choice);
}
void loadChoiceInput(ArrayList list, JSONObject inputData) {
VariantInputData input;
input.type = Input_Classname;
// Check classname -> targetname -> hammerid
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
if(inputData.GetString("targetname", input.name, sizeof(input.name))) {
input.type = Input_Targetname;
} else {
if(inputData.GetString("hammerid", input.name, sizeof(input.name))) {
input.type = Input_HammerId;
} else {
int id = inputData.GetInt("hammerid");
if(id > 0) {
input.type = Input_HammerId;
IntToString(id, input.name, sizeof(input.name));
} else {
LogError("Missing valid input specification (hammerid, classname, targetname)");
return;
}
}
}
}
inputData.GetString("input", input.input, sizeof(input.input));
list.PushArray(input);
}
void loadLumpData(ArrayList list, JSONObject inputData) {
LumpEditData input;
// Check classname -> targetname -> hammerid
if(!inputData.GetString("classname", input.name, sizeof(input.name))) {
if(inputData.GetString("targetname", input.name, sizeof(input.name))) {
input.type = Input_Targetname;
} else {
if(inputData.GetString("hammerid", input.name, sizeof(input.name))) {
input.type = Input_HammerId;
} else {
int id = inputData.GetInt("hammerid");
if(id > 0) {
input.type = Input_HammerId;
IntToString(id, input.name, sizeof(input.name));
} else {
LogError("Missing valid input specification (hammerid, classname, targetname)");
return;
}
}
}
}
inputData.GetString("action", input.action, sizeof(input.action));
inputData.GetString("value", input.value, sizeof(input.value));
list.PushArray(input);
}
void loadChoiceEntity(ArrayList list, JSONObject entityData) {
VariantEntityData entity;
entityData.GetString("model", entity.model, sizeof(entity.model));
if(entityData.GetString("targetname", entity.targetname, sizeof(entity.targetname))) {
Format(entity.targetname, sizeof(entity.targetname), "randomizer_%s", entity.targetname);
}
if(!entityData.GetString("type", entity.type, sizeof(entity.type))) {
entity.type = "prop_dynamic";
} /*else if(entity.type[0] == '_') {
LogError("Invalid custom entity type \"%s\"", entity.type);
return;
}*/
if(StrEqual(entity.type, "move_rope")) {
if(!entityData.HasKey("keyframes")) {
LogError("move_rope entity is missing keyframes: Vec[] property");
return;
}
entity.keyframes = new ArrayList(3);
JSONArray keyframesData = view_as<JSONArray>(entityData.Get("keyframes"));
float vec[3];
for(int i = 0 ; i < keyframesData.Length; i++) {
JSONArray vecArray = view_as<JSONArray>(keyframesData.Get(i));
vec[0] = vecArray.GetFloat(0);
vec[1] = vecArray.GetFloat(1);
vec[2] = vecArray.GetFloat(2);
entity.keyframes.PushArray(vec);
}
}
GetVector(entityData, "origin", entity.origin);
GetVector(entityData, "angles", entity.angles);
GetVector(entityData, "scale", entity.scale);
GetColor(entityData, "color", entity.color, DEFAULT_COLOR);
if(entityData.HasKey("properties")) {
JSONObject propRoot = view_as<JSONObject>(entityData.Get("properties"));
if(propRoot.HasKey("int")) entity.properties.intKv = view_as<JSONObject>(propRoot.Get("int"));
if(propRoot.HasKey("float")) entity.properties.floatKv = view_as<JSONObject>(propRoot.Get("float"));
if(propRoot.HasKey("string")) entity.properties.stringKv = view_as<JSONObject>(propRoot.Get("string"));
}
list.PushArray(entity);
}

View file

@ -0,0 +1,230 @@
bool IsTraverseMapA(const char[] map) {
return String_EndsWith(map, "_a");
}
bool IsTraverseMapB(const char[] map) {
// c4m1_milltown_a was added twice so _escape can pop it off and re-use
return StrEqual(map, "c4m5_milltown_escape") || String_EndsWith(map, "_b");
}
public bool LoadRunGlobalMap(const char[] map, int flags) {
// Unless FLAG_IGNORE_TRAVERSE_STORE, if the map is the _b variant, then load the stored _a value
SceneSelection selection;
// Only load map data if we don't already have it
if(g_MapData.scenes == null || g_selection == null || flags & view_as<int>(FLAG_REFRESH)) {
if(~flags & view_as<int>(FLAG_IGNORE_TRAVERSE_STORE) && IsTraverseMapB(map) ) {
Log("LoadRunGlobal: Trying to load traverse selection");
TraverseData traverse;
if(PopTraverseSelection(traverse)) {
Debug("traverse map: %s", traverse.map);
// Try Load the A variant
if(LoadGlobalMapData(traverse.map, flags)) {
selection = view_as<SceneSelection>(traverse.selection);
}
}
}
if(selection == null) {
// This is called if not traverse map or previous data not found
Log("LoadRunGlobal: Loading & generating selection");
if(!LoadGlobalMapData(map, flags)) {
return false;
}
selection = selectScenes(g_MapData, flags);
}
}
if(selection == null) {
LogError("LoadRunGlobalMap: No selection was loaded");
}
g_selection = selection;
return g_MapData.ApplySelection(selection, flags);
}
void trySelectScene(SceneSelection selection, SceneData scene, int flags) {
// Use the .chance field unless FLAG_ALL_SCENES or FLAG_FORCE_ACTIVE is set
if(~flags & view_as<int>(FLAG_ALL_SCENES) && ~flags & view_as<int>(FLAG_FORCE_ACTIVE) && GetURandomFloat() > scene.chance) {
return;
}
if(scene.variants.Length == 0) {
LogError("Warn: No variants were found for scene \"%s\"", scene.name);
return;
}
// TODO: select variant...
SelectedSceneData aScene;
aScene.name = scene.name;
aScene.selectedVariantIndexes = new ArrayList();
ArrayList choices = new ArrayList();
SceneVariantData choice;
int chosenIndex;
Debug("Scene %s has %d variants", scene.name, scene.variants.Length);
// Weighted random: Push N times dependent on weight
for(int i = 0; i < scene.variants.Length; i++) {
scene.variants.GetArray(i, choice);
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
aScene.selectedVariantIndexes.Push(i);
} else {
if(choice.weight <= 0) {
PrintToServer("Warn: Variant %d in scene %s has invalid weight", i, scene.name);
continue;
}
for(int c = 0; c < choice.weight; c++) {
choices.Push(i);
}
}
}
if(flags & view_as<int>(FLAG_ALL_VARIANTS)) {
} else if(choices.Length > 0) {
// Pick a random variant from list
chosenIndex = GetURandomInt() % choices.Length;
chosenIndex = choices.Get(chosenIndex);
Log("Chosen scene \"%s\" with variant #%d", scene.name, chosenIndex);
aScene.selectedVariantIndexes.Push(chosenIndex);
}
delete choices;
selection.AddScene(aScene);
}
void selectGroups(SceneSelection selection, MapData data, int flags) {
StringMapSnapshot snapshot = data.groups.Snapshot();
char key[MAX_SCENE_NAME_LENGTH];
ArrayList groupList;
SceneData scene;
for(int i = 0; i < snapshot.Length; i++) {
snapshot.GetKey(i, key, sizeof(key));
data.groups.GetValue(key, groupList);
// Select a random scene from the group:
int index = GetURandomInt() % groupList.Length;
index = groupList.Get(index);
data.scenes.GetArray(index, scene);
Debug("Selected scene \"%s\" for group %s (%d members)", scene.name, key, groupList.Length);
trySelectScene(selection, scene, flags);
delete groupList;
}
delete snapshot;
}
void selectForcedScenes(SceneSelection selection, MapData data, int flags) {
// Traverse active scenes, loading any other scene it requires (via .force_scenes)
SelectedSceneData aScene;
SceneVariantData choice;
SceneData scene;
// list of scenes that will need to be forced if not already:
ArrayList forcedScenes = new ArrayList(ByteCountToCells(MAX_SCENE_NAME_LENGTH));
char key[MAX_SCENE_NAME_LENGTH];
for(int i = 0; i < selection.Count; i++) {
selection.Get(i, aScene);
// Load scene from active scene entry
if(!data.scenesKv.GetArray(aScene.name, scene, sizeof(scene))) {
// this shouldn't happen
Log("WARN: scene \"%s\" not found in scene selection", aScene.name);
// can't find scene, ignore
continue;
}
for(int v = 0; v < aScene.selectedVariantIndexes.Length; v++) {
aScene.selectedVariantIndexes.GetArray(v, choice);
// If the choice has forced scenes
if(choice.forcedScenes != null) {
// Add each scene to the list to be added
for(int j = 0; j < choice.forcedScenes.Length; j++) {
choice.forcedScenes.GetString(j, key, sizeof(key));
forcedScenes.PushString(key);
}
}
}
}
if(forcedScenes.Length > 0) {
Debug("Loading %d forced scenes", forcedScenes.Length);
}
// Iterate and activate any forced scenes
for(int i = 0; i < forcedScenes.Length; i++) {
forcedScenes.GetString(i, key, sizeof(key));
// Check if scene was already loaded
bool isSceneAlreadyLoaded = false;
for(int j = 0; j < data.activeScenes.Length; j++) {
data.activeScenes.GetArray(j, aScene);
if(StrEqual(aScene.name, key)) {
isSceneAlreadyLoaded = true;
break;
}
}
if(isSceneAlreadyLoaded) continue;
data.scenesKv.GetArray(key, scene, sizeof(scene));
trySelectScene(selection, scene, flags | view_as<int>(FLAG_FORCE_ACTIVE));
}
delete forcedScenes;
}
// Selects what scenes and its variants to apply and returns list - does not activate
SceneSelection selectScenes(MapData data, int flags = 0) {
SceneData scene;
SceneSelection selection = new SceneSelection();
Profiler profiler = new Profiler();
profiler.Start();
for(int i = 0; i < data.scenes.Length; i++) {
data.scenes.GetArray(i, scene);
if(scene.group[0] == '\0') {
trySelectScene(selection, scene, flags);
}
}
selectGroups(selection, data, flags);
selectForcedScenes(selection, data, flags);
profiler.Stop();
Log("Done generating selection in %.4f seconds", profiler.Time);
return selection;
}
void spawnGascans(MapData data) {
if(data.gascanSpawners != null && data.gascanSpawners.Length > 0) {
// Iterate through every gascan until we run out - picking a random spawner each time
int entity = -1;
char targetname[9];
GascanSpawnerData spawner;
int spawnerCount = data.gascanSpawners.Length;
int count;
while((entity = FindEntityByClassname(entity, "weapon_gascan")) != INVALID_ENT_REFERENCE) {
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
int hammerid = GetEntProp(entity, Prop_Data, "m_iHammerID");
int glowColor = GetEntProp(entity, Prop_Send, "m_glowColorOverride"); // check if white
if(hammerid == 0 && glowColor == 16777215 && targetname[0] == '\0' && !g_gascanSpawners.ContainsKey(entity)) {
// Found a valid gascan, apply a random spawner
int spawnerIndex = GetRandomInt(0, data.gascanSpawners.Length - 1);
data.gascanSpawners.GetArray(spawnerIndex, spawner);
data.gascanSpawners.Erase(spawnerIndex); // only want one can to use this spawner
AssignGascan(entity, spawner);
count++;
}
}
Debug("Assigned %d gascans to %d spawners", count, spawnerCount);
}
}
void activateVariant(SceneVariantData choice, int flags) {
#pragma unused flags
VariantEntityData entity;
for(int i = 0; i < choice.entities.Length; i++) {
choice.entities.GetArray(i, entity);
spawnEntity(entity);
}
if(choice.inputsList.Length > 0) {
VariantInputData input;
for(int i = 0; i < choice.inputsList.Length; i++) {
choice.inputsList.GetArray(i, input);
input.Trigger();
}
}
}

View file

@ -0,0 +1,40 @@
public bool GetVector(JSONObject obj, const char[] key, float out[3]) {
if(!obj.HasKey(key)) return false;
JSONArray vecArray = view_as<JSONArray>(obj.Get(key));
if(vecArray != null) {
out[0] = vecArray.GetFloat(0);
out[1] = vecArray.GetFloat(1);
out[2] = vecArray.GetFloat(2);
}
return true;
}
public void GetColor(JSONObject obj, const char[] key, int out[4], int defaultColor[4]) {
if(obj.HasKey(key)) {
JSONArray vecArray = view_as<JSONArray>(obj.Get(key));
out[0] = vecArray.GetInt(0);
out[1] = vecArray.GetInt(1);
out[2] = vecArray.GetInt(2);
if(vecArray.Length == 4)
out[3] = vecArray.GetInt(3);
else
out[3] = 255;
} else {
out = defaultColor;
}
}
stock JSONArray FromFloatArray(float[] vec, int count) {
JSONArray arr = new JSONArray();
for(int i = 0 ; i < count; i++) {
arr.PushFloat(vec[i]);
}
return arr;
}
stock JSONArray FromIntArray(int[] vec, int count) {
JSONArray arr = new JSONArray();
for(int i = 0 ; i < count; i++) {
arr.PushInt(vec[i]);
}
return arr;
}

View file

@ -55,11 +55,6 @@
#undef REQUIRE_PLUGIN
#include <CreateSurvivorBot>
#define L4D2_WEPUPGFLAG_NONE (0 << 0)
#define L4D2_WEPUPGFLAG_INCENDIARY (1 << 0)
#define L4D2_WEPUPGFLAG_EXPLOSIVE (1 << 1)
#define L4D2_WEPUPGFLAG_LASER (1 << 2)
#define AMMOPACK_ENTID 0
#define AMMOPACK_USERS 1
@ -1779,7 +1774,7 @@ Action Timer_UpdateHud(Handle h) {
void PopulateItems() {
if(g_areItemsPopulated) return;
UpdateSurvivorCount();
PrintToServer("[EPI:TEMP] PopulateItems hasRan=%b finale=%b willRun=%b players=%d", g_areItemsPopulated, L4D_IsMissionFinalMap(true), !g_areItemsPopulated&&IsEPIActive, g_realSurvivorCount);
PrintToServer("[EPI:TEMP] PopulateItems hasRan=%b finale=%b willRun=%b players=%d", g_areItemsPopulated, L4D_IsMissionFinalMap(true), !g_areItemsPopulated&&IsEPIActive(), g_realSurvivorCount);
if(!IsEPIActive()) return;
g_areItemsPopulated = true;
@ -1821,6 +1816,20 @@ void PopulateItems() {
PopulateCabinets();
}
int CalculateExtraDefibCount() {
if(L4D_IsMissionFinalMap()) {
int maxCount = g_survivorCount - 4;
if(maxCount < 0) maxCount = 0;
return DiceRoll(0, maxCount, 2, BIAS_LEFT);
} else if(g_survivorCount > 4) {
float chance = float(g_survivorCount) / 64.0;
return GetRandomFloat() > chance ? 1 : 0;
} else {
return 0;
}
}
void PopulateItemSpawns(int minWalls = 4) {
ArrayList navs = new ArrayList();
L4D_GetAllNavAreas(navs);
@ -1837,6 +1846,9 @@ void PopulateItemSpawns(int minWalls = 4) {
float mapFlowMax = L4D2Direct_GetMapMaxFlowDistance();
PrintToServer("[EPI] PopulateItemSpawns: flow[0, %f]", mapFlowMax);
int maxSpawns = RoundFloat(mapFlowMax / MAX_RANDOM_SPAWNS);
int defibCount = CalculateExtraDefibCount();
bool isFinale = L4D_IsMissionFinalMap();
for(int i = 0; i < navs.Length; i++) {
Address nav = navs.Get(i);
int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav);
@ -1866,8 +1878,19 @@ void PopulateItemSpawns(int minWalls = 4) {
}
if(wpn == -1) continue;
if(++count >= maxSpawns) break;
} else if(defibCount > 0) {
if(isFinale) {
if(spawnFlags & NAV_SPAWN_FINALE) {
CreateWeaponSpawn(pos, "weapon_defibrilator", tier);
defibCount--;
}
} else {
CreateWeaponSpawn(pos, "weapon_defibrilator", tier);
defibCount--;
}
}
}
}
}
PrintToServer("[EPI] Spawned %d/%d new item spawns (tier=%d)", count, maxSpawns, tier);

File diff suppressed because it is too large Load diff